Loading packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/DataConnectionState.kt 0 → 100644 +40 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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.model import android.telephony.TelephonyManager.DATA_CONNECTED import android.telephony.TelephonyManager.DATA_CONNECTING import android.telephony.TelephonyManager.DATA_DISCONNECTED import android.telephony.TelephonyManager.DATA_DISCONNECTING import android.telephony.TelephonyManager.DataState /** Internal enum representation of the telephony data connection states */ enum class DataConnectionState(@DataState val dataState: Int) { Connected(DATA_CONNECTED), Connecting(DATA_CONNECTING), Disconnected(DATA_DISCONNECTED), Disconnecting(DATA_DISCONNECTING), } fun @receiver:DataState Int.toDataConnectionType(): DataConnectionState = when (this) { DATA_CONNECTED -> DataConnectionState.Connected DATA_CONNECTING -> DataConnectionState.Connecting DATA_DISCONNECTED -> DataConnectionState.Disconnected DATA_DISCONNECTING -> DataConnectionState.Disconnecting else -> throw IllegalArgumentException("unknown data state received") } packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt +4 −3 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.telephony.TelephonyCallback.SignalStrengthsListener import android.telephony.TelephonyDisplayInfo import android.telephony.TelephonyManager import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Disconnected /** * Data class containing all of the relevant information for a particular line of service, known as Loading @@ -49,14 +50,14 @@ data class MobileSubscriptionModel( @IntRange(from = 0, to = 4) val primaryLevel: Int = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, /** Comes directly from [DataConnectionStateListener.onDataConnectionStateChanged] */ val dataConnectionState: Int? = null, /** Mapped from [DataConnectionStateListener.onDataConnectionStateChanged] */ val dataConnectionState: DataConnectionState = Disconnected, /** From [DataActivityListener.onDataActivity]. See [TelephonyManager] for the values */ @DataActivityType val dataActivityDirection: Int? = null, /** From [CarrierNetworkListener.onCarrierNetworkChange] */ val carrierNetworkChangeActive: Boolean? = null, val carrierNetworkChangeActive: Boolean = false, /** * From [DisplayInfoListener.onDisplayInfoChanged]. Loading packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt +20 −4 Original line number Diff line number Diff line Loading @@ -31,7 +31,9 @@ import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.statusbar.pipeline.mobile.data.model.DefaultNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.toDataConnectionType import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange import java.lang.IllegalStateException import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher Loading @@ -42,7 +44,7 @@ import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn /** Loading @@ -62,13 +64,15 @@ interface MobileConnectionRepository { * listener + model. */ val subscriptionModelFlow: Flow<MobileSubscriptionModel> /** Observable tracking [TelephonyManager.isDataConnectionAllowed] */ val dataEnabled: Flow<Boolean> } @Suppress("EXPERIMENTAL_IS_NOT_ENABLED") @OptIn(ExperimentalCoroutinesApi::class) class MobileConnectionRepositoryImpl( private val subId: Int, telephonyManager: TelephonyManager, private val telephonyManager: TelephonyManager, bgDispatcher: CoroutineDispatcher, logger: ConnectivityPipelineLogger, scope: CoroutineScope, Loading Loading @@ -127,7 +131,8 @@ class MobileConnectionRepositoryImpl( dataState: Int, networkType: Int ) { state = state.copy(dataConnectionState = dataState) state = state.copy(dataConnectionState = dataState.toDataConnectionType()) trySend(state) } Loading Loading @@ -160,10 +165,21 @@ class MobileConnectionRepositoryImpl( telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback) awaitClose { telephonyManager.unregisterTelephonyCallback(callback) } } .onEach { logger.logOutputChange("mobileSubscriptionModel", it.toString()) } .logOutputChange(logger, "MobileSubscriptionModel") .stateIn(scope, SharingStarted.WhileSubscribed(), state) } /** * There are a few cases where we will need to poll [TelephonyManager] so we can update some * internal state where callbacks aren't provided. Any of those events should be merged into * this flow, which can be used to trigger the polling. */ private val telephonyPollingEvent: Flow<Unit> = subscriptionModelFlow.map {} override val dataEnabled: Flow<Boolean> = telephonyPollingEvent.map { dataConnectionAllowed() } private fun dataConnectionAllowed(): Boolean = telephonyManager.isDataConnectionAllowed class Factory @Inject constructor( Loading packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt +5 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,9 @@ import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map interface MobileIconInteractor { /** Observable for the data enabled state of this connection */ val isDataEnabled: Flow<Boolean> /** Observable for RAT type (network type) indicator */ val networkTypeIconGroup: Flow<MobileIconGroup> Loading @@ -54,6 +57,8 @@ class MobileIconInteractorImpl( ) : MobileIconInteractor { private val mobileStatusInfo = connectionRepository.subscriptionModelFlow override val isDataEnabled: Flow<Boolean> = connectionRepository.dataEnabled /** Observable for the current RAT indicator icon ([MobileIconGroup]) */ override val networkTypeIconGroup: Flow<MobileIconGroup> = combine( Loading packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt +18 −6 Original line number Diff line number Diff line Loading @@ -23,12 +23,14 @@ import com.android.settingslib.SignalIcon.MobileIconGroup import com.android.settingslib.mobile.TelephonyIcons import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy import com.android.systemui.util.CarrierConfigTracker import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow Loading @@ -47,28 +49,38 @@ import kotlinx.coroutines.flow.stateIn * icon */ interface MobileIconsInteractor { /** List of subscriptions, potentially filtered for CBRS */ val filteredSubscriptions: Flow<List<SubscriptionInfo>> /** The icon mapping from network type to [MobileIconGroup] for the default subscription */ val defaultMobileIconMapping: Flow<Map<String, MobileIconGroup>> /** Fallback [MobileIconGroup] in the case where there is no icon in the mapping */ val defaultMobileIconGroup: Flow<MobileIconGroup> /** True once the user has been set up */ val isUserSetup: Flow<Boolean> /** * Vends out a [MobileIconInteractor] tracking the [MobileConnectionRepository] for the given * subId. Will throw if the ID is invalid */ fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor } @Suppress("EXPERIMENTAL_IS_NOT_ENABLED") @OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class MobileIconsInteractorImpl @Inject constructor( private val mobileSubscriptionRepo: MobileConnectionsRepository, private val mobileConnectionsRepo: MobileConnectionsRepository, private val carrierConfigTracker: CarrierConfigTracker, private val mobileMappingsProxy: MobileMappingsProxy, userSetupRepo: UserSetupRepository, @Application private val scope: CoroutineScope, ) : MobileIconsInteractor { private val activeMobileDataSubscriptionId = mobileSubscriptionRepo.activeMobileDataSubscriptionId mobileConnectionsRepo.activeMobileDataSubscriptionId private val unfilteredSubscriptions: Flow<List<SubscriptionInfo>> = mobileSubscriptionRepo.subscriptionsFlow mobileConnectionsRepo.subscriptionsFlow /** * Generally, SystemUI wants to show iconography for each subscription that is listed by Loading Loading @@ -119,13 +131,13 @@ constructor( * subscription Id. This mapping is the same for every subscription. */ override val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>> = mobileSubscriptionRepo.defaultDataSubRatConfig mobileConnectionsRepo.defaultDataSubRatConfig .map { mobileMappingsProxy.mapIconSets(it) } .stateIn(scope, SharingStarted.WhileSubscribed(), initialValue = mapOf()) /** If there is no mapping in [defaultMobileIconMapping], then use this default icon group */ override val defaultMobileIconGroup: StateFlow<MobileIconGroup> = mobileSubscriptionRepo.defaultDataSubRatConfig mobileConnectionsRepo.defaultDataSubRatConfig .map { mobileMappingsProxy.getDefaultIcons(it) } .stateIn(scope, SharingStarted.WhileSubscribed(), initialValue = TelephonyIcons.G) Loading @@ -137,6 +149,6 @@ constructor( defaultMobileIconMapping, defaultMobileIconGroup, mobileMappingsProxy, mobileSubscriptionRepo.getRepoForSubId(subId), mobileConnectionsRepo.getRepoForSubId(subId), ) } Loading
packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/DataConnectionState.kt 0 → 100644 +40 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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.model import android.telephony.TelephonyManager.DATA_CONNECTED import android.telephony.TelephonyManager.DATA_CONNECTING import android.telephony.TelephonyManager.DATA_DISCONNECTED import android.telephony.TelephonyManager.DATA_DISCONNECTING import android.telephony.TelephonyManager.DataState /** Internal enum representation of the telephony data connection states */ enum class DataConnectionState(@DataState val dataState: Int) { Connected(DATA_CONNECTED), Connecting(DATA_CONNECTING), Disconnected(DATA_DISCONNECTED), Disconnecting(DATA_DISCONNECTING), } fun @receiver:DataState Int.toDataConnectionType(): DataConnectionState = when (this) { DATA_CONNECTED -> DataConnectionState.Connected DATA_CONNECTING -> DataConnectionState.Connecting DATA_DISCONNECTED -> DataConnectionState.Disconnected DATA_DISCONNECTING -> DataConnectionState.Disconnecting else -> throw IllegalArgumentException("unknown data state received") }
packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt +4 −3 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.telephony.TelephonyCallback.SignalStrengthsListener import android.telephony.TelephonyDisplayInfo import android.telephony.TelephonyManager import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Disconnected /** * Data class containing all of the relevant information for a particular line of service, known as Loading @@ -49,14 +50,14 @@ data class MobileSubscriptionModel( @IntRange(from = 0, to = 4) val primaryLevel: Int = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, /** Comes directly from [DataConnectionStateListener.onDataConnectionStateChanged] */ val dataConnectionState: Int? = null, /** Mapped from [DataConnectionStateListener.onDataConnectionStateChanged] */ val dataConnectionState: DataConnectionState = Disconnected, /** From [DataActivityListener.onDataActivity]. See [TelephonyManager] for the values */ @DataActivityType val dataActivityDirection: Int? = null, /** From [CarrierNetworkListener.onCarrierNetworkChange] */ val carrierNetworkChangeActive: Boolean? = null, val carrierNetworkChangeActive: Boolean = false, /** * From [DisplayInfoListener.onDisplayInfoChanged]. Loading
packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt +20 −4 Original line number Diff line number Diff line Loading @@ -31,7 +31,9 @@ import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.statusbar.pipeline.mobile.data.model.DefaultNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.model.toDataConnectionType import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange import java.lang.IllegalStateException import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher Loading @@ -42,7 +44,7 @@ import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn /** Loading @@ -62,13 +64,15 @@ interface MobileConnectionRepository { * listener + model. */ val subscriptionModelFlow: Flow<MobileSubscriptionModel> /** Observable tracking [TelephonyManager.isDataConnectionAllowed] */ val dataEnabled: Flow<Boolean> } @Suppress("EXPERIMENTAL_IS_NOT_ENABLED") @OptIn(ExperimentalCoroutinesApi::class) class MobileConnectionRepositoryImpl( private val subId: Int, telephonyManager: TelephonyManager, private val telephonyManager: TelephonyManager, bgDispatcher: CoroutineDispatcher, logger: ConnectivityPipelineLogger, scope: CoroutineScope, Loading Loading @@ -127,7 +131,8 @@ class MobileConnectionRepositoryImpl( dataState: Int, networkType: Int ) { state = state.copy(dataConnectionState = dataState) state = state.copy(dataConnectionState = dataState.toDataConnectionType()) trySend(state) } Loading Loading @@ -160,10 +165,21 @@ class MobileConnectionRepositoryImpl( telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback) awaitClose { telephonyManager.unregisterTelephonyCallback(callback) } } .onEach { logger.logOutputChange("mobileSubscriptionModel", it.toString()) } .logOutputChange(logger, "MobileSubscriptionModel") .stateIn(scope, SharingStarted.WhileSubscribed(), state) } /** * There are a few cases where we will need to poll [TelephonyManager] so we can update some * internal state where callbacks aren't provided. Any of those events should be merged into * this flow, which can be used to trigger the polling. */ private val telephonyPollingEvent: Flow<Unit> = subscriptionModelFlow.map {} override val dataEnabled: Flow<Boolean> = telephonyPollingEvent.map { dataConnectionAllowed() } private fun dataConnectionAllowed(): Boolean = telephonyManager.isDataConnectionAllowed class Factory @Inject constructor( Loading
packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt +5 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,9 @@ import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map interface MobileIconInteractor { /** Observable for the data enabled state of this connection */ val isDataEnabled: Flow<Boolean> /** Observable for RAT type (network type) indicator */ val networkTypeIconGroup: Flow<MobileIconGroup> Loading @@ -54,6 +57,8 @@ class MobileIconInteractorImpl( ) : MobileIconInteractor { private val mobileStatusInfo = connectionRepository.subscriptionModelFlow override val isDataEnabled: Flow<Boolean> = connectionRepository.dataEnabled /** Observable for the current RAT indicator icon ([MobileIconGroup]) */ override val networkTypeIconGroup: Flow<MobileIconGroup> = combine( Loading
packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt +18 −6 Original line number Diff line number Diff line Loading @@ -23,12 +23,14 @@ import com.android.settingslib.SignalIcon.MobileIconGroup import com.android.settingslib.mobile.TelephonyIcons import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy import com.android.systemui.util.CarrierConfigTracker import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow Loading @@ -47,28 +49,38 @@ import kotlinx.coroutines.flow.stateIn * icon */ interface MobileIconsInteractor { /** List of subscriptions, potentially filtered for CBRS */ val filteredSubscriptions: Flow<List<SubscriptionInfo>> /** The icon mapping from network type to [MobileIconGroup] for the default subscription */ val defaultMobileIconMapping: Flow<Map<String, MobileIconGroup>> /** Fallback [MobileIconGroup] in the case where there is no icon in the mapping */ val defaultMobileIconGroup: Flow<MobileIconGroup> /** True once the user has been set up */ val isUserSetup: Flow<Boolean> /** * Vends out a [MobileIconInteractor] tracking the [MobileConnectionRepository] for the given * subId. Will throw if the ID is invalid */ fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor } @Suppress("EXPERIMENTAL_IS_NOT_ENABLED") @OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class MobileIconsInteractorImpl @Inject constructor( private val mobileSubscriptionRepo: MobileConnectionsRepository, private val mobileConnectionsRepo: MobileConnectionsRepository, private val carrierConfigTracker: CarrierConfigTracker, private val mobileMappingsProxy: MobileMappingsProxy, userSetupRepo: UserSetupRepository, @Application private val scope: CoroutineScope, ) : MobileIconsInteractor { private val activeMobileDataSubscriptionId = mobileSubscriptionRepo.activeMobileDataSubscriptionId mobileConnectionsRepo.activeMobileDataSubscriptionId private val unfilteredSubscriptions: Flow<List<SubscriptionInfo>> = mobileSubscriptionRepo.subscriptionsFlow mobileConnectionsRepo.subscriptionsFlow /** * Generally, SystemUI wants to show iconography for each subscription that is listed by Loading Loading @@ -119,13 +131,13 @@ constructor( * subscription Id. This mapping is the same for every subscription. */ override val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>> = mobileSubscriptionRepo.defaultDataSubRatConfig mobileConnectionsRepo.defaultDataSubRatConfig .map { mobileMappingsProxy.mapIconSets(it) } .stateIn(scope, SharingStarted.WhileSubscribed(), initialValue = mapOf()) /** If there is no mapping in [defaultMobileIconMapping], then use this default icon group */ override val defaultMobileIconGroup: StateFlow<MobileIconGroup> = mobileSubscriptionRepo.defaultDataSubRatConfig mobileConnectionsRepo.defaultDataSubRatConfig .map { mobileMappingsProxy.getDefaultIcons(it) } .stateIn(scope, SharingStarted.WhileSubscribed(), initialValue = TelephonyIcons.G) Loading @@ -137,6 +149,6 @@ constructor( defaultMobileIconMapping, defaultMobileIconGroup, mobileMappingsProxy, mobileSubscriptionRepo.getRepoForSubId(subId), mobileConnectionsRepo.getRepoForSubId(subId), ) }