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

Commit 47059222 authored by Steve Elliott's avatar Steve Elliott
Browse files

[kairos] Have icon adapter track latest interactor

Presently, various view-models depend on the interactor returned from
MobileIconsInteractor#getMobileConnectionInteractorForSubId remaining
"alive" indefinitely, even if the connection disappears and returns.
This is due to a "desync" between the set of active connections and the
set of subscriptionIds.

When the ui layer is migrated to Kairos this will no longer be an issue,
because the new Kairos versions expose IconInteractors directly as
opposed to the indirection of the subscription id. For now though, the adapter must respect the behavior of the original API.

Flag: com.android.systemui.status_bar_mobile_icon_kairos
Bug: 383172066
Test: atest
Change-Id: Ic5a82b6df6723fa423dbc6b4deb7982ad5727068
parent 9184e14d
Loading
Loading
Loading
Loading
+15 −15
Original line number Diff line number Diff line
@@ -61,31 +61,31 @@ interface MobileIconInteractor {
     * consider this connection to be serving data, and thus want to show a network type icon, when
     * data is connected. Other data connection states would typically cause us not to show the icon
     */
    val isDataConnected: StateFlow<Boolean>
    val isDataConnected: Flow<Boolean>

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

    /** True if this connection is emergency only */
    val isEmergencyOnly: StateFlow<Boolean>
    val isEmergencyOnly: Flow<Boolean>

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

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

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

    /** Observable for RAT type (network type) indicator */
    val networkTypeIconGroup: StateFlow<NetworkTypeIconModel>
    val networkTypeIconGroup: Flow<NetworkTypeIconModel>

    /** Whether or not to show the slice attribution */
    val showSliceAttribution: StateFlow<Boolean>
    val showSliceAttribution: Flow<Boolean>

    /** True if this connection is satellite-based */
    val isNonTerrestrial: StateFlow<Boolean>
    val isNonTerrestrial: Flow<Boolean>

    /**
     * Provider name for this network connection. The name can be one of 3 values:
@@ -95,7 +95,7 @@ interface MobileIconInteractor {
     *    override in [connectionInfo.operatorAlphaShort], a value that is derived from
     *    [ServiceState]
     */
    val networkName: StateFlow<NetworkNameModel>
    val networkName: Flow<NetworkNameModel>

    /**
     * Provider name for this network connection. The name can be one of 3 values:
@@ -108,26 +108,26 @@ interface MobileIconInteractor {
     * TODO(b/296600321): De-duplicate this field with [networkName] after determining the data
     *   provided is identical
     */
    val carrierName: StateFlow<String>
    val carrierName: Flow<String>

    /** True if there is only one active subscription. */
    val isSingleCarrier: StateFlow<Boolean>
    val isSingleCarrier: Flow<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
     * connection to be roaming while carrier network change is active
     */
    val isRoaming: StateFlow<Boolean>
    val isRoaming: Flow<Boolean>

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

    /** See [MobileConnectionRepository.isAllowedDuringAirplaneMode]. */
    val isAllowedDuringAirplaneMode: StateFlow<Boolean>
    val isAllowedDuringAirplaneMode: Flow<Boolean>

    /** True when in carrier network change mode */
    val carrierNetworkChangeActive: StateFlow<Boolean>
    val carrierNetworkChangeActive: Flow<Boolean>
}

/** Interactor for a single mobile connection. This connection _should_ have one subscription ID */
+43 −1
Original line number Diff line number Diff line
@@ -32,11 +32,20 @@ import com.android.systemui.kairos.map
import com.android.systemui.kairos.mapValues
import com.android.systemui.kairos.toColdConflatedFlow
import com.android.systemui.kairosBuilder
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.TableLogBufferFactory
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepositoryKairos
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.MOBILE_CONNECTION_BUFFER_SIZE
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.tableBufferLogName
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.mobile.util.MobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository
import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
import dagger.Provides
import dagger.multibindings.ElementsIntoSet
import javax.inject.Inject
@@ -45,6 +54,8 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn

@ExperimentalKairosApi
@@ -60,6 +71,7 @@ constructor(
    context: Context,
    mobileMappingsProxy: MobileMappingsProxy,
    private val userSetupRepo: UserSetupRepository,
    private val logFactory: TableLogBufferFactory,
) : MobileIconsInteractor, KairosBuilder by kairosBuilder() {

    private val interactorsBySubIdK = buildIncremental {
@@ -158,7 +170,37 @@ constructor(
        get() = repo.isDeviceEmergencyCallCapable

    override fun getMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
        interactorsBySubId.value[subId] ?: error("Unknown subscription id: $subId")
        object : MobileIconInteractor {
            override val tableLogBuffer: TableLogBuffer =
                logFactory.getOrCreate(tableBufferLogName(subId), MOBILE_CONNECTION_BUFFER_SIZE)
            override val activity: Flow<DataActivityModel> = latest { activity }
            override val mobileIsDefault: Flow<Boolean> = latest { mobileIsDefault }
            override val isDataConnected: Flow<Boolean> = latest { isDataConnected }
            override val isInService: Flow<Boolean> = latest { isInService }
            override val isEmergencyOnly: Flow<Boolean> = latest { isEmergencyOnly }
            override val isDataEnabled: Flow<Boolean> = latest { isDataEnabled }
            override val alwaysShowDataRatIcon: Flow<Boolean> = latest { alwaysShowDataRatIcon }
            override val signalLevelIcon: Flow<SignalIconModel> = latest { signalLevelIcon }
            override val networkTypeIconGroup: Flow<NetworkTypeIconModel> = latest {
                networkTypeIconGroup
            }
            override val showSliceAttribution: Flow<Boolean> = latest { showSliceAttribution }
            override val isNonTerrestrial: Flow<Boolean> = latest { isNonTerrestrial }
            override val networkName: Flow<NetworkNameModel> = latest { networkName }
            override val carrierName: Flow<String> = latest { carrierName }
            override val isSingleCarrier: Flow<Boolean> = latest { isSingleCarrier }
            override val isRoaming: Flow<Boolean> = latest { isRoaming }
            override val isForceHidden: Flow<Boolean> = latest { isForceHidden }
            override val isAllowedDuringAirplaneMode: Flow<Boolean> = latest {
                isAllowedDuringAirplaneMode
            }
            override val carrierNetworkChangeActive: Flow<Boolean> = latest {
                carrierNetworkChangeActive
            }

            private fun <T> latest(block: MobileIconInteractor.() -> Flow<T>): Flow<T> =
                interactorsBySubId.flatMapLatestConflated { it[subId]?.block() ?: emptyFlow() }
        }

    @dagger.Module
    object Module {