1 /* <lambda>null2 * Copyright (C) 2022 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.data.repository.prod 18 19 import androidx.annotation.VisibleForTesting 20 import com.android.systemui.dagger.qualifiers.Application 21 import com.android.systemui.log.table.TableLogBuffer 22 import com.android.systemui.log.table.TableLogBufferFactory 23 import com.android.systemui.log.table.logDiffsForTable 24 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel 25 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository 26 import javax.inject.Inject 27 import kotlinx.coroutines.CoroutineScope 28 import kotlinx.coroutines.ExperimentalCoroutinesApi 29 import kotlinx.coroutines.flow.MutableStateFlow 30 import kotlinx.coroutines.flow.SharingStarted 31 import kotlinx.coroutines.flow.StateFlow 32 import kotlinx.coroutines.flow.flatMapLatest 33 import kotlinx.coroutines.flow.mapLatest 34 import kotlinx.coroutines.flow.stateIn 35 36 /** 37 * A repository that fully implements a mobile connection. 38 * 39 * This connection could either be a typical mobile connection (see [MobileConnectionRepositoryImpl] 40 * or a carrier merged connection (see [CarrierMergedConnectionRepository]). This repository 41 * switches between the two types of connections based on whether the connection is currently 42 * carrier merged (see [setIsCarrierMerged]). 43 */ 44 @Suppress("EXPERIMENTAL_IS_NOT_ENABLED") 45 @OptIn(ExperimentalCoroutinesApi::class) 46 class FullMobileConnectionRepository( 47 override val subId: Int, 48 startingIsCarrierMerged: Boolean, 49 override val tableLogBuffer: TableLogBuffer, 50 private val defaultNetworkName: NetworkNameModel, 51 private val networkNameSeparator: String, 52 @Application scope: CoroutineScope, 53 private val mobileRepoFactory: MobileConnectionRepositoryImpl.Factory, 54 private val carrierMergedRepoFactory: CarrierMergedConnectionRepository.Factory, 55 ) : MobileConnectionRepository { 56 /** 57 * Sets whether this connection is a typical mobile connection or a carrier merged connection. 58 */ 59 fun setIsCarrierMerged(isCarrierMerged: Boolean) { 60 _isCarrierMerged.value = isCarrierMerged 61 } 62 63 /** 64 * Returns true if this repo is currently for a carrier merged connection and false otherwise. 65 */ 66 @VisibleForTesting fun getIsCarrierMerged() = _isCarrierMerged.value 67 68 private val _isCarrierMerged = MutableStateFlow(startingIsCarrierMerged) 69 private val isCarrierMerged: StateFlow<Boolean> = 70 _isCarrierMerged 71 .logDiffsForTable( 72 tableLogBuffer, 73 columnPrefix = "", 74 columnName = "isCarrierMerged", 75 initialValue = startingIsCarrierMerged, 76 ) 77 .stateIn(scope, SharingStarted.WhileSubscribed(), startingIsCarrierMerged) 78 79 private val mobileRepo: MobileConnectionRepository by lazy { 80 mobileRepoFactory.build( 81 subId, 82 tableLogBuffer, 83 defaultNetworkName, 84 networkNameSeparator, 85 ) 86 } 87 88 private val carrierMergedRepo: MobileConnectionRepository by lazy { 89 carrierMergedRepoFactory.build(subId, tableLogBuffer) 90 } 91 92 @VisibleForTesting 93 internal val activeRepo: StateFlow<MobileConnectionRepository> = run { 94 val initial = 95 if (startingIsCarrierMerged) { 96 carrierMergedRepo 97 } else { 98 mobileRepo 99 } 100 101 this.isCarrierMerged 102 .mapLatest { isCarrierMerged -> 103 if (isCarrierMerged) { 104 carrierMergedRepo 105 } else { 106 mobileRepo 107 } 108 } 109 .stateIn(scope, SharingStarted.WhileSubscribed(), initial) 110 } 111 112 override val cdmaRoaming = 113 activeRepo 114 .flatMapLatest { it.cdmaRoaming } 115 .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.cdmaRoaming.value) 116 117 override val isEmergencyOnly = 118 activeRepo 119 .flatMapLatest { it.isEmergencyOnly } 120 .logDiffsForTable( 121 tableLogBuffer, 122 columnPrefix = "", 123 columnName = COL_EMERGENCY, 124 activeRepo.value.isEmergencyOnly.value 125 ) 126 .stateIn( 127 scope, 128 SharingStarted.WhileSubscribed(), 129 activeRepo.value.isEmergencyOnly.value 130 ) 131 132 override val isRoaming = 133 activeRepo 134 .flatMapLatest { it.isRoaming } 135 .logDiffsForTable( 136 tableLogBuffer, 137 columnPrefix = "", 138 columnName = COL_ROAMING, 139 activeRepo.value.isRoaming.value 140 ) 141 .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isRoaming.value) 142 143 override val operatorAlphaShort = 144 activeRepo 145 .flatMapLatest { it.operatorAlphaShort } 146 .logDiffsForTable( 147 tableLogBuffer, 148 columnPrefix = "", 149 columnName = COL_OPERATOR, 150 activeRepo.value.operatorAlphaShort.value 151 ) 152 .stateIn( 153 scope, 154 SharingStarted.WhileSubscribed(), 155 activeRepo.value.operatorAlphaShort.value 156 ) 157 158 override val isInService = 159 activeRepo 160 .flatMapLatest { it.isInService } 161 .logDiffsForTable( 162 tableLogBuffer, 163 columnPrefix = "", 164 columnName = COL_IS_IN_SERVICE, 165 activeRepo.value.isInService.value 166 ) 167 .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isInService.value) 168 169 override val isGsm = 170 activeRepo 171 .flatMapLatest { it.isGsm } 172 .logDiffsForTable( 173 tableLogBuffer, 174 columnPrefix = "", 175 columnName = COL_IS_GSM, 176 activeRepo.value.isGsm.value 177 ) 178 .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isGsm.value) 179 180 override val cdmaLevel = 181 activeRepo 182 .flatMapLatest { it.cdmaLevel } 183 .logDiffsForTable( 184 tableLogBuffer, 185 columnPrefix = "", 186 columnName = COL_CDMA_LEVEL, 187 activeRepo.value.cdmaLevel.value 188 ) 189 .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.cdmaLevel.value) 190 191 override val primaryLevel = 192 activeRepo 193 .flatMapLatest { it.primaryLevel } 194 .logDiffsForTable( 195 tableLogBuffer, 196 columnPrefix = "", 197 columnName = COL_PRIMARY_LEVEL, 198 activeRepo.value.primaryLevel.value 199 ) 200 .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.primaryLevel.value) 201 202 override val dataConnectionState = 203 activeRepo 204 .flatMapLatest { it.dataConnectionState } 205 .logDiffsForTable( 206 tableLogBuffer, 207 columnPrefix = "", 208 activeRepo.value.dataConnectionState.value 209 ) 210 .stateIn( 211 scope, 212 SharingStarted.WhileSubscribed(), 213 activeRepo.value.dataConnectionState.value 214 ) 215 216 override val dataActivityDirection = 217 activeRepo 218 .flatMapLatest { it.dataActivityDirection } 219 .logDiffsForTable( 220 tableLogBuffer, 221 columnPrefix = "", 222 activeRepo.value.dataActivityDirection.value 223 ) 224 .stateIn( 225 scope, 226 SharingStarted.WhileSubscribed(), 227 activeRepo.value.dataActivityDirection.value 228 ) 229 230 override val carrierNetworkChangeActive = 231 activeRepo 232 .flatMapLatest { it.carrierNetworkChangeActive } 233 .logDiffsForTable( 234 tableLogBuffer, 235 columnPrefix = "", 236 columnName = COL_CARRIER_NETWORK_CHANGE, 237 activeRepo.value.carrierNetworkChangeActive.value 238 ) 239 .stateIn( 240 scope, 241 SharingStarted.WhileSubscribed(), 242 activeRepo.value.carrierNetworkChangeActive.value 243 ) 244 245 override val resolvedNetworkType = 246 activeRepo 247 .flatMapLatest { it.resolvedNetworkType } 248 .logDiffsForTable( 249 tableLogBuffer, 250 columnPrefix = "", 251 activeRepo.value.resolvedNetworkType.value 252 ) 253 .stateIn( 254 scope, 255 SharingStarted.WhileSubscribed(), 256 activeRepo.value.resolvedNetworkType.value 257 ) 258 259 override val dataEnabled = 260 activeRepo 261 .flatMapLatest { it.dataEnabled } 262 .logDiffsForTable( 263 tableLogBuffer, 264 columnPrefix = "", 265 columnName = "dataEnabled", 266 initialValue = activeRepo.value.dataEnabled.value, 267 ) 268 .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.dataEnabled.value) 269 270 override val numberOfLevels = 271 activeRepo 272 .flatMapLatest { it.numberOfLevels } 273 .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.numberOfLevels.value) 274 275 override val networkName = 276 activeRepo 277 .flatMapLatest { it.networkName } 278 .logDiffsForTable( 279 tableLogBuffer, 280 columnPrefix = "", 281 initialValue = activeRepo.value.networkName.value, 282 ) 283 .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.networkName.value) 284 285 class Factory 286 @Inject 287 constructor( 288 @Application private val scope: CoroutineScope, 289 private val logFactory: TableLogBufferFactory, 290 private val mobileRepoFactory: MobileConnectionRepositoryImpl.Factory, 291 private val carrierMergedRepoFactory: CarrierMergedConnectionRepository.Factory, 292 ) { 293 fun build( 294 subId: Int, 295 startingIsCarrierMerged: Boolean, 296 defaultNetworkName: NetworkNameModel, 297 networkNameSeparator: String, 298 ): FullMobileConnectionRepository { 299 val mobileLogger = 300 logFactory.getOrCreate(tableBufferLogName(subId), MOBILE_CONNECTION_BUFFER_SIZE) 301 302 return FullMobileConnectionRepository( 303 subId, 304 startingIsCarrierMerged, 305 mobileLogger, 306 defaultNetworkName, 307 networkNameSeparator, 308 scope, 309 mobileRepoFactory, 310 carrierMergedRepoFactory, 311 ) 312 } 313 314 companion object { 315 /** The buffer size to use for logging. */ 316 const val MOBILE_CONNECTION_BUFFER_SIZE = 100 317 318 /** Returns a log buffer name for a mobile connection with the given [subId]. */ 319 fun tableBufferLogName(subId: Int): String = "MobileConnectionLog[$subId]" 320 } 321 } 322 323 companion object { 324 const val COL_EMERGENCY = "emergencyOnly" 325 const val COL_ROAMING = "roaming" 326 const val COL_OPERATOR = "operatorName" 327 const val COL_IS_IN_SERVICE = "isInService" 328 const val COL_IS_GSM = "isGsm" 329 const val COL_CDMA_LEVEL = "cdmaLevel" 330 const val COL_PRIMARY_LEVEL = "primaryLevel" 331 const val COL_CARRIER_NETWORK_CHANGE = "carrierNetworkChangeActive" 332 } 333 } 334