• 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 android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
20 import android.telephony.TelephonyManager
21 import android.util.Log
22 import com.android.systemui.dagger.SysUISingleton
23 import com.android.systemui.dagger.qualifiers.Application
24 import com.android.systemui.log.table.TableLogBuffer
25 import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
26 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
27 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
28 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
29 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
30 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
31 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
32 import javax.inject.Inject
33 import kotlinx.coroutines.CoroutineScope
34 import kotlinx.coroutines.flow.Flow
35 import kotlinx.coroutines.flow.MutableStateFlow
36 import kotlinx.coroutines.flow.SharingStarted
37 import kotlinx.coroutines.flow.StateFlow
38 import kotlinx.coroutines.flow.asStateFlow
39 import kotlinx.coroutines.flow.combine
40 import kotlinx.coroutines.flow.map
41 import kotlinx.coroutines.flow.stateIn
42 
43 /**
44  * A repository implementation for a carrier merged (aka VCN) network. A carrier merged network is
45  * delivered to SysUI as a wifi network (see [WifiNetworkModel.CarrierMerged], but is visually
46  * displayed as a mobile network triangle.
47  *
48  * See [android.net.wifi.WifiInfo.isCarrierMerged] for more information.
49  *
50  * See [MobileConnectionRepositoryImpl] for a repository implementation of a typical mobile
51  * connection.
52  */
53 class CarrierMergedConnectionRepository(
54     override val subId: Int,
55     override val tableLogBuffer: TableLogBuffer,
56     private val telephonyManager: TelephonyManager,
57     @Application private val scope: CoroutineScope,
58     val wifiRepository: WifiRepository,
59 ) : MobileConnectionRepository {
60     init {
61         if (telephonyManager.subscriptionId != subId) {
62             throw IllegalStateException(
63                 "CarrierMergedRepo: TelephonyManager should be created with subId($subId). " +
64                     "Found ${telephonyManager.subscriptionId} instead."
65             )
66         }
67     }
68 
69     /**
70      * Outputs the carrier merged network to use, or null if we don't have a valid carrier merged
71      * network.
72      */
73     private val network: Flow<WifiNetworkModel.CarrierMerged?> =
74         combine(
75             wifiRepository.isWifiEnabled,
76             wifiRepository.isWifiDefault,
77             wifiRepository.wifiNetwork,
78         ) { isEnabled, isDefault, network ->
79             when {
80                 !isEnabled -> null
81                 !isDefault -> null
82                 network !is WifiNetworkModel.CarrierMerged -> null
83                 network.subscriptionId != subId -> {
84                     Log.w(
85                         TAG,
86                         "Connection repo subId=$subId " +
87                             "does not equal wifi repo subId=${network.subscriptionId}; " +
88                             "not showing carrier merged"
89                     )
90                     null
91                 }
92                 else -> network
93             }
94         }
95 
96     override val cdmaRoaming: StateFlow<Boolean> = MutableStateFlow(ROAMING).asStateFlow()
97 
98     override val networkName: StateFlow<NetworkNameModel> =
99         network
100             // The SIM operator name should be the same throughout the lifetime of a subId, **but**
101             // it may not be available when this repo is created because it takes time to load. To
102             // be safe, we re-fetch it each time the network has changed.
103             .map { NetworkNameModel.SimDerived(telephonyManager.simOperatorName) }
104             .stateIn(
105                 scope,
106                 SharingStarted.WhileSubscribed(),
107                 NetworkNameModel.SimDerived(telephonyManager.simOperatorName),
108             )
109 
110     override val numberOfLevels: StateFlow<Int> =
111         wifiRepository.wifiNetwork
112             .map {
113                 if (it is WifiNetworkModel.CarrierMerged) {
114                     it.numberOfLevels
115                 } else {
116                     DEFAULT_NUM_LEVELS
117                 }
118             }
119             .stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_NUM_LEVELS)
120 
121     override val primaryLevel =
122         network
123             .map { it?.level ?: SIGNAL_STRENGTH_NONE_OR_UNKNOWN }
124             .stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
125 
126     override val cdmaLevel =
127         network
128             .map { it?.level ?: SIGNAL_STRENGTH_NONE_OR_UNKNOWN }
129             .stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
130 
131     override val dataActivityDirection = wifiRepository.wifiActivity
132 
133     override val resolvedNetworkType =
134         network
135             .map {
136                 if (it != null) {
137                     ResolvedNetworkType.CarrierMergedNetworkType
138                 } else {
139                     ResolvedNetworkType.UnknownNetworkType
140                 }
141             }
142             .stateIn(
143                 scope,
144                 SharingStarted.WhileSubscribed(),
145                 ResolvedNetworkType.UnknownNetworkType
146             )
147 
148     override val dataConnectionState =
149         network
150             .map {
151                 if (it != null) {
152                     DataConnectionState.Connected
153                 } else {
154                     DataConnectionState.Disconnected
155                 }
156             }
157             .stateIn(scope, SharingStarted.WhileSubscribed(), DataConnectionState.Disconnected)
158 
159     override val isRoaming = MutableStateFlow(false).asStateFlow()
160     override val isEmergencyOnly = MutableStateFlow(false).asStateFlow()
161     override val operatorAlphaShort = MutableStateFlow(null).asStateFlow()
162     override val isInService = MutableStateFlow(true).asStateFlow()
163     override val isGsm = MutableStateFlow(false).asStateFlow()
164     override val carrierNetworkChangeActive = MutableStateFlow(false).asStateFlow()
165 
166     override val dataEnabled: StateFlow<Boolean> = wifiRepository.isWifiEnabled
167 
168     companion object {
169         // Carrier merged is never roaming
170         private const val ROAMING = false
171     }
172 
173     @SysUISingleton
174     class Factory
175     @Inject
176     constructor(
177         private val telephonyManager: TelephonyManager,
178         @Application private val scope: CoroutineScope,
179         private val wifiRepository: WifiRepository,
180     ) {
181         fun build(
182             subId: Int,
183             mobileLogger: TableLogBuffer,
184         ): MobileConnectionRepository {
185             return CarrierMergedConnectionRepository(
186                 subId,
187                 mobileLogger,
188                 telephonyManager.createForSubscriptionId(subId),
189                 scope,
190                 wifiRepository,
191             )
192         }
193     }
194 }
195 
196 private const val TAG = "CarrierMergedConnectionRepository"
197