Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 376a02bd authored by Evan Laird's avatar Evan Laird
Browse files

[Sb refactor] Remove some unused fields from MobileIconInteractor

Now that MobileIconInteractor provides an [icon] field, we can remove
some unused public fields that were all being calculated in the view
model. This simplifies the overall structure of the interactor -> view
model relationship, but it comes at the cost of requiring us to use the
real interactor implementations in tests.

Oh did I mention I updated the MobileIconViewModel tests to use the real
interactors. You now have to be pretty familiar with the data model
itself to understand what is happening in the tests. And there is more
work to be done with the fake repos, which still rely on the
externally-defined MobileMappings class.

Test: tests in statusbar/pipeline/*
Bug: 265342892
Change-Id: Ie85d92ad9d29f9d6d0c45ad72ca1c5e51482229b
parent a388ad63
Loading
Loading
Loading
Loading
+5 −29
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.pipeline.mobile.domain.interactor

import android.content.Context
import android.telephony.CarrierConfigManager
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.graph.SignalDrawable
import com.android.settingslib.mobile.MobileIconCarrierIdOverrides
@@ -62,25 +61,15 @@ interface MobileIconInteractor {
     */
    val isDataConnected: StateFlow<Boolean>

    /** Only true if mobile is the default transport but is not validated, otherwise false */
    val isDefaultConnectionFailed: StateFlow<Boolean>

    /** True if we consider this connection to be in service, i.e. can make calls */
    val isInService: StateFlow<Boolean>

    // TODO(b/256839546): clarify naming of default vs active
    /** True if we want to consider the data connection enabled */
    val isDefaultDataEnabled: StateFlow<Boolean>

    /** Observable for the data enabled state of this connection */
    val isDataEnabled: StateFlow<Boolean>

    /** True if the RAT icon should always be displayed and false otherwise. */
    val alwaysShowDataRatIcon: StateFlow<Boolean>

    /** True if the CDMA level should be preferred over the primary level. */
    val alwaysUseCdmaLevel: StateFlow<Boolean>

    /** Canonical representation of the current mobile signal strength as a triangle. */
    val signalLevelIcon: StateFlow<SignalIconModel>

@@ -113,9 +102,6 @@ interface MobileIconInteractor {
    /** True if there is only one active subscription. */
    val isSingleCarrier: StateFlow<Boolean>

    /** True if this line of service is emergency-only */
    val isEmergencyOnly: StateFlow<Boolean>

    /**
     * True if this connection is considered roaming. The roaming bit can come from [ServiceState],
     * or directly from the telephony manager's CDMA ERI number value. Note that we don't consider a
@@ -123,12 +109,6 @@ interface MobileIconInteractor {
     */
    val isRoaming: StateFlow<Boolean>

    /** Int describing the connection strength. 0-4 OR 1-5. See [numberOfLevels] */
    val level: StateFlow<Int>

    /** Based on [CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL], either 4 or 5 */
    val numberOfLevels: StateFlow<Int>

    /** See [MobileIconsInteractor.isForceHidden]. */
    val isForceHidden: Flow<Boolean>

@@ -146,12 +126,12 @@ class MobileIconInteractorImpl(
    @Application scope: CoroutineScope,
    defaultSubscriptionHasDataEnabled: StateFlow<Boolean>,
    override val alwaysShowDataRatIcon: StateFlow<Boolean>,
    override val alwaysUseCdmaLevel: StateFlow<Boolean>,
    alwaysUseCdmaLevel: StateFlow<Boolean>,
    override val isSingleCarrier: StateFlow<Boolean>,
    override val mobileIsDefault: StateFlow<Boolean>,
    defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>,
    defaultMobileIconGroup: StateFlow<MobileIconGroup>,
    override val isDefaultConnectionFailed: StateFlow<Boolean>,
    isDefaultConnectionFailed: StateFlow<Boolean>,
    override val isForceHidden: Flow<Boolean>,
    connectionRepository: MobileConnectionRepository,
    private val context: Context,
@@ -175,8 +155,6 @@ class MobileIconInteractorImpl(
            .distinctUntilChanged()
            .stateIn(scope, SharingStarted.WhileSubscribed(), false)

    override val isDefaultDataEnabled = defaultSubscriptionHasDataEnabled

    override val networkName =
        combine(connectionRepository.operatorAlphaShort, connectionRepository.networkName) {
                operatorAlphaShort,
@@ -260,8 +238,6 @@ class MobileIconInteractorImpl(
                DefaultIcon(defaultMobileIconGroup.value),
            )

    override val isEmergencyOnly = connectionRepository.isEmergencyOnly

    override val isRoaming: StateFlow<Boolean> =
        combine(
                connectionRepository.carrierNetworkChangeActive,
@@ -279,7 +255,7 @@ class MobileIconInteractorImpl(
            }
            .stateIn(scope, SharingStarted.WhileSubscribed(), false)

    override val level: StateFlow<Int> =
    private val level: StateFlow<Int> =
        combine(
                connectionRepository.isGsm,
                connectionRepository.primaryLevel,
@@ -295,7 +271,7 @@ class MobileIconInteractorImpl(
            }
            .stateIn(scope, SharingStarted.WhileSubscribed(), 0)

    override val numberOfLevels: StateFlow<Int> =
    private val numberOfLevels: StateFlow<Int> =
        connectionRepository.numberOfLevels.stateIn(
            scope,
            SharingStarted.WhileSubscribed(),
@@ -314,7 +290,7 @@ class MobileIconInteractorImpl(
    /** Whether or not to show the error state of [SignalDrawable] */
    private val showExclamationMark: StateFlow<Boolean> =
        combine(
                isDefaultDataEnabled,
                defaultSubscriptionHasDataEnabled,
                isDefaultConnectionFailed,
                isInService,
            ) { isDefaultDataEnabled, isDefaultConnectionFailed, isInService ->
+22 −0
Original line number Diff line number Diff line
@@ -64,6 +64,28 @@ class FakeMobileConnectionRepository(
        _dataEnabled.value = enabled
    }

    /**
     * Set [primaryLevel] and [cdmaLevel]. Convenient when you don't care about the connection type
     */
    fun setAllLevels(level: Int) {
        cdmaLevel.value = level
        primaryLevel.value = level
    }

    /**
     * Set both [isRoaming] and [cdmaRoaming] properties, in the event that you don't care about the
     * connection type
     */
    fun setAllRoaming(roaming: Boolean) {
        isRoaming.value = roaming
        cdmaRoaming.value = roaming
    }

    /** Set the correct [resolvedNetworkType] for the given group via its lookup key */
    fun setNetworkTypeKey(key: String) {
        resolvedNetworkType.value = ResolvedNetworkType.DefaultNetworkType(key)
    }

    companion object {
        const val DEFAULT_NETWORK_NAME = "default name"
    }
+2 −41
Original line number Diff line number Diff line
@@ -16,11 +16,9 @@

package com.android.systemui.statusbar.pipeline.mobile.domain.interactor

import android.telephony.CellSignalStrength
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel
import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
@@ -31,8 +29,6 @@ class FakeMobileIconInteractor(
) : MobileIconInteractor {
    override val alwaysShowDataRatIcon = MutableStateFlow(false)

    override val alwaysUseCdmaLevel = MutableStateFlow(false)

    override val activity =
        MutableStateFlow(
            DataActivityModel(
@@ -56,14 +52,8 @@ class FakeMobileIconInteractor(

    override val carrierName = MutableStateFlow("demo mode")

    private val _isEmergencyOnly = MutableStateFlow(false)
    override val isEmergencyOnly = _isEmergencyOnly

    override val isRoaming = MutableStateFlow(false)

    private val _isFailedConnection = MutableStateFlow(false)
    override val isDefaultConnectionFailed = _isFailedConnection

    override val isDataConnected = MutableStateFlow(true)

    override val isInService = MutableStateFlow(true)
@@ -71,15 +61,6 @@ class FakeMobileIconInteractor(
    private val _isDataEnabled = MutableStateFlow(true)
    override val isDataEnabled = _isDataEnabled

    private val _isDefaultDataEnabled = MutableStateFlow(true)
    override val isDefaultDataEnabled = _isDefaultDataEnabled

    private val _level = MutableStateFlow(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
    override val level = _level

    private val _numberOfLevels = MutableStateFlow(DEFAULT_NUM_LEVELS)
    override val numberOfLevels = _numberOfLevels

    override val isForceHidden = MutableStateFlow(false)

    override val isAllowedDuringAirplaneMode = MutableStateFlow(false)
@@ -87,34 +68,14 @@ class FakeMobileIconInteractor(
    override val signalLevelIcon: MutableStateFlow<SignalIconModel> =
        MutableStateFlow(
            SignalIconModel(
                level = level.value,
                numberOfLevels = numberOfLevels.value,
                level = 0,
                numberOfLevels = 4,
                showExclamationMark = false,
                carrierNetworkChange = false,
            )
        )

    fun setIsEmergencyOnly(emergency: Boolean) {
        _isEmergencyOnly.value = emergency
    }

    fun setIsDataEnabled(enabled: Boolean) {
        _isDataEnabled.value = enabled
    }

    fun setIsDefaultDataEnabled(disabled: Boolean) {
        _isDefaultDataEnabled.value = disabled
    }

    fun setIsFailedConnection(failed: Boolean) {
        _isFailedConnection.value = failed
    }

    fun setLevel(level: Int) {
        _level.value = level
    }

    fun setNumberOfLevels(num: Int) {
        _numberOfLevels.value = num
    }
}
+6 −63
Original line number Diff line number Diff line
@@ -81,19 +81,6 @@ class MobileIconInteractorTest : SysuiTestCase() {
        connectionRepository.isInService.value = true
    }

    @Test
    fun gsm_level_default_unknown() =
        testScope.runTest {
            connectionRepository.isGsm.value = true

            var latest: Int? = null
            val job = underTest.level.onEach { latest = it }.launchIn(this)

            assertThat(latest).isEqualTo(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)

            job.cancel()
        }

    @Test
    fun gsm_usesGsmLevel() =
        testScope.runTest {
@@ -102,7 +89,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
            connectionRepository.cdmaLevel.value = CDMA_LEVEL

            var latest: Int? = null
            val job = underTest.level.onEach { latest = it }.launchIn(this)
            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)

            assertThat(latest).isEqualTo(GSM_LEVEL)

@@ -118,7 +105,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
            mobileIconsInteractor.alwaysUseCdmaLevel.value = true

            var latest: Int? = null
            val job = underTest.level.onEach { latest = it }.launchIn(this)
            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)

            assertThat(latest).isEqualTo(GSM_LEVEL)

@@ -131,7 +118,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
            connectionRepository.isGsm.value = false

            var latest: Int? = null
            val job = underTest.level.onEach { latest = it }.launchIn(this)
            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)

            assertThat(latest).isEqualTo(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
            job.cancel()
@@ -146,7 +133,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
            mobileIconsInteractor.alwaysUseCdmaLevel.value = true

            var latest: Int? = null
            val job = underTest.level.onEach { latest = it }.launchIn(this)
            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)

            assertThat(latest).isEqualTo(CDMA_LEVEL)

@@ -162,7 +149,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
            mobileIconsInteractor.alwaysUseCdmaLevel.value = false

            var latest: Int? = null
            val job = underTest.level.onEach { latest = it }.launchIn(this)
            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)

            assertThat(latest).isEqualTo(GSM_LEVEL)

@@ -173,7 +160,7 @@ class MobileIconInteractorTest : SysuiTestCase() {
    fun numberOfLevels_comesFromRepo() =
        testScope.runTest {
            var latest: Int? = null
            val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this)
            val job = underTest.signalLevelIcon.onEach { latest = it.numberOfLevels }.launchIn(this)

            connectionRepository.numberOfLevels.value = 5
            assertThat(latest).isEqualTo(5)
@@ -298,50 +285,6 @@ class MobileIconInteractorTest : SysuiTestCase() {
            job.cancel()
        }

    @Test
    fun alwaysUseCdmaLevel_matchesParent() =
        testScope.runTest {
            var latest: Boolean? = null
            val job = underTest.alwaysUseCdmaLevel.onEach { latest = it }.launchIn(this)

            mobileIconsInteractor.alwaysUseCdmaLevel.value = true
            assertThat(latest).isTrue()

            mobileIconsInteractor.alwaysUseCdmaLevel.value = false
            assertThat(latest).isFalse()

            job.cancel()
        }

    @Test
    fun test_isDefaultDataEnabled_matchesParent() =
        testScope.runTest {
            var latest: Boolean? = null
            val job = underTest.isDefaultDataEnabled.onEach { latest = it }.launchIn(this)

            mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = true
            assertThat(latest).isTrue()

            mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = false
            assertThat(latest).isFalse()

            job.cancel()
        }

    @Test
    fun test_isDefaultConnectionFailed_matchedParent() =
        testScope.runTest {
            val job = underTest.isDefaultConnectionFailed.launchIn(this)

            mobileIconsInteractor.isDefaultConnectionFailed.value = false
            assertThat(underTest.isDefaultConnectionFailed.value).isFalse()

            mobileIconsInteractor.isDefaultConnectionFailed.value = true
            assertThat(underTest.isDefaultConnectionFailed.value).isTrue()

            job.cancel()
        }

    @Test
    fun dataState_connected() =
        testScope.runTest {
+77 −17
Original line number Diff line number Diff line
@@ -17,18 +17,26 @@
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.log.table.TableLogBuffer
import com.android.systemui.statusbar.connectivity.MobileIconCarrierIdOverridesFake
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.mobile.domain.interactor.FakeMobileIconInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractorImpl
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.domain.model.SignalIconModel
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModelTest.Companion.defaultSignal
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
import com.android.systemui.util.CarrierConfigTracker
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -50,11 +58,18 @@ class LocationBasedMobileIconViewModelTest : SysuiTestCase() {
    private lateinit var homeIcon: HomeMobileIconViewModel
    private lateinit var qsIcon: QsMobileIconViewModel
    private lateinit var keyguardIcon: KeyguardMobileIconViewModel
    private lateinit var interactor: FakeMobileIconInteractor
    private lateinit var iconsInteractor: MobileIconsInteractor
    private lateinit var interactor: MobileIconInteractor
    private lateinit var connectionsRepository: FakeMobileConnectionsRepository
    private lateinit var repository: FakeMobileConnectionRepository
    private lateinit var airplaneModeInteractor: AirplaneModeInteractor

    private val connectivityRepository = FakeConnectivityRepository()

    @Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
    @Mock private lateinit var constants: ConnectivityConstants
    @Mock private lateinit var tableLogBuffer: TableLogBuffer
    @Mock private lateinit var carrierConfigTracker: CarrierConfigTracker

    private val testDispatcher = UnconfinedTestDispatcher()
    private val testScope = TestScope(testDispatcher)
@@ -67,17 +82,51 @@ class LocationBasedMobileIconViewModelTest : SysuiTestCase() {
                FakeAirplaneModeRepository(),
                FakeConnectivityRepository(),
            )
        interactor = FakeMobileIconInteractor(tableLogBuffer)
        interactor.apply {
            setLevel(1)
            setIsDefaultDataEnabled(true)
            setIsFailedConnection(false)
            setIsEmergencyOnly(false)
            setNumberOfLevels(4)
            networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
            isDataConnected.value = true
            signalLevelIcon.value = defaultSignal()
        connectionsRepository =
            FakeMobileConnectionsRepository(FakeMobileMappingsProxy(), tableLogBuffer)
        repository =
            FakeMobileConnectionRepository(SUB_1_ID, tableLogBuffer).apply {
                isInService.value = true
                cdmaLevel.value = 1
                primaryLevel.value = 1
                isEmergencyOnly.value = false
                numberOfLevels.value = 4
                resolvedNetworkType.value = ResolvedNetworkType.DefaultNetworkType(lookupKey = "3G")
                dataConnectionState.value = DataConnectionState.Connected
            }

        connectionsRepository.activeMobileDataRepository.value = repository

        connectivityRepository.apply { setMobileConnected() }

        iconsInteractor =
            MobileIconsInteractorImpl(
                connectionsRepository,
                carrierConfigTracker,
                tableLogBuffer,
                connectivityRepository,
                FakeUserSetupRepository(),
                testScope.backgroundScope,
                context,
            )

        interactor =
            MobileIconInteractorImpl(
                testScope.backgroundScope,
                iconsInteractor.activeDataConnectionHasDataEnabled,
                iconsInteractor.alwaysShowDataRatIcon,
                iconsInteractor.alwaysUseCdmaLevel,
                iconsInteractor.isSingleCarrier,
                iconsInteractor.mobileIsDefault,
                iconsInteractor.defaultMobileIconMapping,
                iconsInteractor.defaultMobileIconGroup,
                iconsInteractor.isDefaultConnectionFailed,
                iconsInteractor.isForceHidden,
                repository,
                context,
                MobileIconCarrierIdOverridesFake()
            )

        commonImpl =
            MobileIconViewModel(
                SUB_1_ID,
@@ -110,7 +159,7 @@ class LocationBasedMobileIconViewModelTest : SysuiTestCase() {
            assertThat(latestQs).isEqualTo(expected)
            assertThat(latestKeyguard).isEqualTo(expected)

            interactor.signalLevelIcon.value = defaultSignal(level = 2)
            repository.setAllLevels(2)
            expected = defaultSignal(level = 2)

            assertThat(latestHome).isEqualTo(expected)
@@ -124,5 +173,16 @@ class LocationBasedMobileIconViewModelTest : SysuiTestCase() {

    companion object {
        private const val SUB_1_ID = 1
        private const val NUM_LEVELS = 4

        /** Convenience constructor for these tests */
        fun defaultSignal(level: Int = 1): SignalIconModel {
            return SignalIconModel(
                level,
                NUM_LEVELS,
                showExclamationMark = false,
                carrierNetworkChange = false,
            )
        }
    }
}
Loading