1 /* <lambda>null2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar.pipeline.mobile.domain.interactor 18 19 import android.content.Context 20 import com.android.settingslib.SignalIcon 21 import com.android.settingslib.mobile.MobileMappings 22 import com.android.systemui.Flags 23 import com.android.systemui.KairosActivatable 24 import com.android.systemui.KairosBuilder 25 import com.android.systemui.dagger.SysUISingleton 26 import com.android.systemui.dagger.qualifiers.Application 27 import com.android.systemui.kairos.ExperimentalKairosApi 28 import com.android.systemui.kairos.KairosNetwork 29 import com.android.systemui.kairos.buildSpec 30 import com.android.systemui.kairos.combine 31 import com.android.systemui.kairos.map 32 import com.android.systemui.kairos.mapValues 33 import com.android.systemui.kairos.toColdConflatedFlow 34 import com.android.systemui.kairosBuilder 35 import com.android.systemui.log.table.TableLogBuffer 36 import com.android.systemui.log.table.TableLogBufferFactory 37 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel 38 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel 39 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository 40 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepositoryKairos 41 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.MOBILE_CONNECTION_BUFFER_SIZE 42 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.tableBufferLogName 43 import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel 44 import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel 45 import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy 46 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel 47 import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository 48 import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated 49 import dagger.Provides 50 import dagger.multibindings.ElementsIntoSet 51 import javax.inject.Inject 52 import javax.inject.Provider 53 import kotlinx.coroutines.CoroutineScope 54 import kotlinx.coroutines.flow.Flow 55 import kotlinx.coroutines.flow.SharingStarted 56 import kotlinx.coroutines.flow.StateFlow 57 import kotlinx.coroutines.flow.emptyFlow 58 import kotlinx.coroutines.flow.map 59 import kotlinx.coroutines.flow.stateIn 60 61 @ExperimentalKairosApi 62 @SysUISingleton 63 class MobileIconsInteractorKairosAdapter 64 @Inject 65 constructor( 66 private val kairosInteractor: MobileIconsInteractorKairos, 67 private val repo: MobileConnectionsRepository, 68 repoK: MobileConnectionsRepositoryKairos, 69 kairosNetwork: KairosNetwork, 70 @Application scope: CoroutineScope, 71 context: Context, 72 mobileMappingsProxy: MobileMappingsProxy, 73 private val userSetupRepo: UserSetupRepository, 74 private val logFactory: TableLogBufferFactory, 75 ) : MobileIconsInteractor, KairosBuilder by kairosBuilder() { 76 77 private val interactorsBySubIdK = buildIncremental { 78 kairosInteractor.icons 79 .mapValues { (subId, interactor) -> 80 buildSpec { MobileIconInteractorKairosAdapter(interactor) } 81 } 82 .applyLatestSpecForKey() 83 } 84 85 private val interactorsBySubId = 86 interactorsBySubIdK 87 .toColdConflatedFlow(kairosNetwork) 88 .stateIn(scope, SharingStarted.Eagerly, emptyMap()) 89 90 override val defaultDataSubId: Flow<Int?> 91 get() = repo.defaultDataSubId 92 93 override val mobileIsDefault: StateFlow<Boolean> = 94 kairosInteractor.mobileIsDefault 95 .toColdConflatedFlow(kairosNetwork) 96 .stateIn(scope, SharingStarted.WhileSubscribed(), repo.mobileIsDefault.value) 97 98 override val filteredSubscriptions: Flow<List<SubscriptionModel>> = 99 kairosInteractor.filteredSubscriptions.toColdConflatedFlow(kairosNetwork) 100 101 override val icons: StateFlow<List<MobileIconInteractor>> = 102 interactorsBySubIdK 103 .map { it.values.toList() } 104 .toColdConflatedFlow(kairosNetwork) 105 .stateIn(scope, SharingStarted.WhileSubscribed(), emptyList()) 106 107 override val isStackable: StateFlow<Boolean> = 108 kairosInteractor.isStackable 109 .toColdConflatedFlow(kairosNetwork) 110 .stateIn(scope, SharingStarted.WhileSubscribed(), false) 111 112 override val activeMobileDataSubscriptionId: StateFlow<Int?> 113 get() = repo.activeMobileDataSubscriptionId 114 115 override val activeDataConnectionHasDataEnabled: StateFlow<Boolean> = 116 kairosInteractor.activeDataConnectionHasDataEnabled 117 .toColdConflatedFlow(kairosNetwork) 118 .stateIn(scope, SharingStarted.WhileSubscribed(), false) 119 120 override val activeDataIconInteractor: StateFlow<MobileIconInteractor?> = 121 combine(repoK.activeMobileDataSubscriptionId, interactorsBySubIdK) { subId, interactors -> 122 interactors[subId] 123 } 124 .toColdConflatedFlow(kairosNetwork) 125 .stateIn(scope, SharingStarted.WhileSubscribed(), null) 126 127 override val alwaysShowDataRatIcon: StateFlow<Boolean> = 128 kairosInteractor.alwaysShowDataRatIcon 129 .toColdConflatedFlow(kairosNetwork) 130 .stateIn(scope, SharingStarted.WhileSubscribed(), false) 131 132 override val alwaysUseCdmaLevel: StateFlow<Boolean> = 133 kairosInteractor.alwaysUseCdmaLevel 134 .toColdConflatedFlow(kairosNetwork) 135 .stateIn(scope, SharingStarted.WhileSubscribed(), false) 136 137 override val isSingleCarrier: StateFlow<Boolean> = 138 kairosInteractor.isSingleCarrier 139 .toColdConflatedFlow(kairosNetwork) 140 .stateIn(scope, SharingStarted.WhileSubscribed(), false) 141 142 override val defaultMobileIconMapping: StateFlow<Map<String, SignalIcon.MobileIconGroup>> = 143 kairosInteractor.defaultMobileIconMapping 144 .toColdConflatedFlow(kairosNetwork) 145 .stateIn(scope, SharingStarted.WhileSubscribed(), emptyMap()) 146 147 override val defaultMobileIconGroup: StateFlow<SignalIcon.MobileIconGroup> = 148 kairosInteractor.defaultMobileIconGroup 149 .toColdConflatedFlow(kairosNetwork) 150 .stateIn( 151 scope, 152 SharingStarted.WhileSubscribed(), 153 mobileMappingsProxy.getDefaultIcons(MobileMappings.Config.readConfig(context)), 154 ) 155 156 override val isDefaultConnectionFailed: StateFlow<Boolean> = 157 kairosInteractor.isDefaultConnectionFailed 158 .toColdConflatedFlow(kairosNetwork) 159 .stateIn(scope, SharingStarted.WhileSubscribed(), false) 160 161 override val isUserSetUp: StateFlow<Boolean> 162 get() = userSetupRepo.isUserSetUp 163 164 override val isForceHidden: Flow<Boolean> = 165 kairosInteractor.isForceHidden 166 .toColdConflatedFlow(kairosNetwork) 167 .stateIn(scope, SharingStarted.WhileSubscribed(), false) 168 169 override val isDeviceInEmergencyCallsOnlyMode: Flow<Boolean> 170 get() = repo.isDeviceEmergencyCallCapable 171 172 override fun getMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor = 173 object : MobileIconInteractor { 174 override val tableLogBuffer: TableLogBuffer = 175 logFactory.getOrCreate(tableBufferLogName(subId), MOBILE_CONNECTION_BUFFER_SIZE) 176 override val activity: Flow<DataActivityModel> = latest { activity } 177 override val mobileIsDefault: Flow<Boolean> = latest { mobileIsDefault } 178 override val isDataConnected: Flow<Boolean> = latest { isDataConnected } 179 override val isInService: Flow<Boolean> = latest { isInService } 180 override val isEmergencyOnly: Flow<Boolean> = latest { isEmergencyOnly } 181 override val isDataEnabled: Flow<Boolean> = latest { isDataEnabled } 182 override val alwaysShowDataRatIcon: Flow<Boolean> = latest { alwaysShowDataRatIcon } 183 override val signalLevelIcon: Flow<SignalIconModel> = latest { signalLevelIcon } 184 override val networkTypeIconGroup: Flow<NetworkTypeIconModel> = latest { 185 networkTypeIconGroup 186 } 187 override val showSliceAttribution: Flow<Boolean> = latest { showSliceAttribution } 188 override val isNonTerrestrial: Flow<Boolean> = latest { isNonTerrestrial } 189 override val networkName: Flow<NetworkNameModel> = latest { networkName } 190 override val carrierName: Flow<String> = latest { carrierName } 191 override val isSingleCarrier: Flow<Boolean> = latest { isSingleCarrier } 192 override val isRoaming: Flow<Boolean> = latest { isRoaming } 193 override val isForceHidden: Flow<Boolean> = latest { isForceHidden } 194 override val isAllowedDuringAirplaneMode: Flow<Boolean> = latest { 195 isAllowedDuringAirplaneMode 196 } 197 override val carrierNetworkChangeActive: Flow<Boolean> = latest { 198 carrierNetworkChangeActive 199 } 200 201 private fun <T> latest(block: MobileIconInteractor.() -> Flow<T>): Flow<T> = 202 interactorsBySubId.flatMapLatestConflated { it[subId]?.block() ?: emptyFlow() } 203 } 204 205 @dagger.Module 206 object Module { 207 @Provides 208 @ElementsIntoSet 209 fun kairosActivatable( 210 impl: Provider<MobileIconsInteractorKairosAdapter> 211 ): Set<@JvmSuppressWildcards KairosActivatable> = 212 if (Flags.statusBarMobileIconKairos()) setOf(impl.get()) else emptySet() 213 } 214 } 215