• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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