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.annotation.SuppressLint
20 import android.content.BroadcastReceiver
21 import android.content.Context
22 import android.content.Intent
23 import android.content.IntentFilter
24 import android.net.ConnectivityManager
25 import android.net.ConnectivityManager.NetworkCallback
26 import android.net.Network
27 import android.net.NetworkCapabilities
28 import android.net.NetworkRequest
29 import android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
30 import android.telephony.CellSignalStrengthCdma
31 import android.telephony.ServiceState
32 import android.telephony.SignalStrength
33 import android.telephony.SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX
34 import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
35 import android.telephony.TelephonyCallback
36 import android.telephony.TelephonyDisplayInfo
37 import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
38 import android.telephony.TelephonyManager
39 import android.telephony.TelephonyManager.ERI_FLASH
40 import android.telephony.TelephonyManager.ERI_ON
41 import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID
42 import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
43 import android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID
44 import com.android.settingslib.Utils
45 import com.android.systemui.broadcast.BroadcastDispatcher
46 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
47 import com.android.systemui.dagger.qualifiers.Application
48 import com.android.systemui.dagger.qualifiers.Background
49 import com.android.systemui.flags.FeatureFlagsClassic
50 import com.android.systemui.flags.Flags.ROAMING_INDICATOR_VIA_DISPLAY_INFO
51 import com.android.systemui.log.table.TableLogBuffer
52 import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
53 import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Disconnected
54 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
55 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
56 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
57 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
58 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
59 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
60 import com.android.systemui.statusbar.pipeline.mobile.data.model.toDataConnectionType
61 import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
62 import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
63 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
64 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
65 import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
66 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
67 import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
68 import javax.inject.Inject
69 import kotlinx.coroutines.CoroutineDispatcher
70 import kotlinx.coroutines.CoroutineScope
71 import kotlinx.coroutines.ExperimentalCoroutinesApi
72 import kotlinx.coroutines.asExecutor
73 import kotlinx.coroutines.channels.awaitClose
74 import kotlinx.coroutines.flow.Flow
75 import kotlinx.coroutines.flow.MutableStateFlow
76 import kotlinx.coroutines.flow.SharingStarted
77 import kotlinx.coroutines.flow.StateFlow
78 import kotlinx.coroutines.flow.asStateFlow
79 import kotlinx.coroutines.flow.callbackFlow
80 import kotlinx.coroutines.flow.filter
81 import kotlinx.coroutines.flow.flowOn
82 import kotlinx.coroutines.flow.map
83 import kotlinx.coroutines.flow.mapLatest
84 import kotlinx.coroutines.flow.mapNotNull
85 import kotlinx.coroutines.flow.onStart
86 import kotlinx.coroutines.flow.scan
87 import kotlinx.coroutines.flow.stateIn
88 import kotlinx.coroutines.withContext
89 
90 /**
91  * A repository implementation for a typical mobile connection (as opposed to a carrier merged
92  * connection -- see [CarrierMergedConnectionRepository]).
93  */
94 @Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
95 @OptIn(ExperimentalCoroutinesApi::class)
96 class MobileConnectionRepositoryImpl(
97     override val subId: Int,
98     private val context: Context,
99     subscriptionModel: Flow<SubscriptionModel?>,
100     defaultNetworkName: NetworkNameModel,
101     networkNameSeparator: String,
102     connectivityManager: ConnectivityManager,
103     private val telephonyManager: TelephonyManager,
104     systemUiCarrierConfig: SystemUiCarrierConfig,
105     broadcastDispatcher: BroadcastDispatcher,
106     private val mobileMappingsProxy: MobileMappingsProxy,
107     private val bgDispatcher: CoroutineDispatcher,
108     logger: MobileInputLogger,
109     override val tableLogBuffer: TableLogBuffer,
110     flags: FeatureFlagsClassic,
111     scope: CoroutineScope,
112 ) : MobileConnectionRepository {
113     init {
114         if (telephonyManager.subscriptionId != subId) {
115             throw IllegalStateException(
116                 "MobileRepo: TelephonyManager should be created with subId($subId). " +
117                     "Found ${telephonyManager.subscriptionId} instead."
118             )
119         }
120     }
121 
122     /**
123      * This flow defines the single shared connection to system_server via TelephonyCallback. Any
124      * new callback should be added to this listener and funneled through callbackEvents via a data
125      * class. See [CallbackEvent] for defining new callbacks.
126      *
127      * The reason we need to do this is because TelephonyManager limits the number of registered
128      * listeners per-process, so we don't want to create a new listener for every callback.
129      *
130      * A note on the design for back pressure here: We don't control _which_ telephony callback
131      * comes in first, since we register every relevant bit of information as a batch. E.g., if a
132      * downstream starts collecting on a field which is backed by
133      * [TelephonyCallback.ServiceStateListener], it's not possible for us to guarantee that _that_
134      * callback comes in -- the first callback could very well be
135      * [TelephonyCallback.DataActivityListener], which would promptly be dropped if we didn't keep
136      * it tracked. We use the [scan] operator here to track the most recent callback of _each type_
137      * here. See [TelephonyCallbackState] to see how the callbacks are stored.
138      */
139     private val callbackEvents: StateFlow<TelephonyCallbackState> = run {
140         val initial = TelephonyCallbackState()
141         callbackFlow {
142                 val callback =
143                     object :
144                         TelephonyCallback(),
145                         TelephonyCallback.CarrierNetworkListener,
146                         TelephonyCallback.CarrierRoamingNtnModeListener,
147                         TelephonyCallback.DataActivityListener,
148                         TelephonyCallback.DataConnectionStateListener,
149                         TelephonyCallback.DataEnabledListener,
150                         TelephonyCallback.DisplayInfoListener,
151                         TelephonyCallback.ServiceStateListener,
152                         TelephonyCallback.SignalStrengthsListener {
153 
154                         override fun onCarrierNetworkChange(active: Boolean) {
155                             logger.logOnCarrierNetworkChange(active, subId)
156                             trySend(CallbackEvent.OnCarrierNetworkChange(active))
157                         }
158 
159                         override fun onCarrierRoamingNtnModeChanged(active: Boolean) {
160                             logger.logOnCarrierRoamingNtnModeChanged(active)
161                             trySend(CallbackEvent.OnCarrierRoamingNtnModeChanged(active))
162                         }
163 
164                         override fun onDataActivity(direction: Int) {
165                             logger.logOnDataActivity(direction, subId)
166                             trySend(CallbackEvent.OnDataActivity(direction))
167                         }
168 
169                         override fun onDataEnabledChanged(enabled: Boolean, reason: Int) {
170                             logger.logOnDataEnabledChanged(enabled, subId)
171                             trySend(CallbackEvent.OnDataEnabledChanged(enabled))
172                         }
173 
174                         override fun onDataConnectionStateChanged(
175                             dataState: Int,
176                             networkType: Int
177                         ) {
178                             logger.logOnDataConnectionStateChanged(dataState, networkType, subId)
179                             trySend(CallbackEvent.OnDataConnectionStateChanged(dataState))
180                         }
181 
182                         override fun onDisplayInfoChanged(
183                             telephonyDisplayInfo: TelephonyDisplayInfo
184                         ) {
185                             logger.logOnDisplayInfoChanged(telephonyDisplayInfo, subId)
186                             trySend(CallbackEvent.OnDisplayInfoChanged(telephonyDisplayInfo))
187                         }
188 
189                         override fun onServiceStateChanged(serviceState: ServiceState) {
190                             logger.logOnServiceStateChanged(serviceState, subId)
191                             trySend(CallbackEvent.OnServiceStateChanged(serviceState))
192                         }
193 
194                         override fun onSignalStrengthsChanged(signalStrength: SignalStrength) {
195                             logger.logOnSignalStrengthsChanged(signalStrength, subId)
196                             trySend(CallbackEvent.OnSignalStrengthChanged(signalStrength))
197                         }
198                     }
199                 telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
200                 awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
201             }
202             .flowOn(bgDispatcher)
203             .scan(initial = initial) { state, event -> state.applyEvent(event) }
204             .stateIn(scope = scope, started = SharingStarted.WhileSubscribed(), initial)
205     }
206 
207     override val isEmergencyOnly =
208         callbackEvents
209             .mapNotNull { it.onServiceStateChanged }
210             .map { it.serviceState.isEmergencyOnly }
211             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
212 
213     override val isRoaming =
214         if (flags.isEnabled(ROAMING_INDICATOR_VIA_DISPLAY_INFO)) {
215                 callbackEvents
216                     .mapNotNull { it.onDisplayInfoChanged }
217                     .map { it.telephonyDisplayInfo.isRoaming }
218             } else {
219                 callbackEvents
220                     .mapNotNull { it.onServiceStateChanged }
221                     .map { it.serviceState.roaming }
222             }
223             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
224 
225     override val operatorAlphaShort =
226         callbackEvents
227             .mapNotNull { it.onServiceStateChanged }
228             .map { it.serviceState.operatorAlphaShort }
229             .stateIn(scope, SharingStarted.WhileSubscribed(), null)
230 
231     override val isInService =
232         callbackEvents
233             .mapNotNull { it.onServiceStateChanged }
234             .map { Utils.isInService(it.serviceState) }
235             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
236 
237     override val isNonTerrestrial =
238         callbackEvents
239             .mapNotNull { it.onCarrierRoamingNtnModeChanged }
240             .map { it.active }
241             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
242 
243     override val isGsm =
244         callbackEvents
245             .mapNotNull { it.onSignalStrengthChanged }
246             .map { it.signalStrength.isGsm }
247             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
248 
249     override val cdmaLevel =
250         callbackEvents
251             .mapNotNull { it.onSignalStrengthChanged }
252             .map {
253                 it.signalStrength.getCellSignalStrengths(CellSignalStrengthCdma::class.java).let {
254                     strengths ->
255                     if (strengths.isNotEmpty()) {
256                         strengths[0].level
257                     } else {
258                         SIGNAL_STRENGTH_NONE_OR_UNKNOWN
259                     }
260                 }
261             }
262             .stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
263 
264     override val primaryLevel =
265         callbackEvents
266             .mapNotNull { it.onSignalStrengthChanged }
267             .map { it.signalStrength.level }
268             .stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
269 
270     override val dataConnectionState =
271         callbackEvents
272             .mapNotNull { it.onDataConnectionStateChanged }
273             .map { it.dataState.toDataConnectionType() }
274             .stateIn(scope, SharingStarted.WhileSubscribed(), Disconnected)
275 
276     override val dataActivityDirection =
277         callbackEvents
278             .mapNotNull { it.onDataActivity }
279             .map { it.direction.toMobileDataActivityModel() }
280             .stateIn(
281                 scope,
282                 SharingStarted.WhileSubscribed(),
283                 DataActivityModel(hasActivityIn = false, hasActivityOut = false)
284             )
285 
286     override val carrierNetworkChangeActive =
287         callbackEvents
288             .mapNotNull { it.onCarrierNetworkChange }
289             .map { it.active }
290             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
291 
292     override val resolvedNetworkType =
293         callbackEvents
294             .mapNotNull { it.onDisplayInfoChanged }
295             .map {
296                 if (it.telephonyDisplayInfo.overrideNetworkType != OVERRIDE_NETWORK_TYPE_NONE) {
297                     OverrideNetworkType(
298                         mobileMappingsProxy.toIconKeyOverride(
299                             it.telephonyDisplayInfo.overrideNetworkType
300                         )
301                     )
302                 } else if (it.telephonyDisplayInfo.networkType != NETWORK_TYPE_UNKNOWN) {
303                     DefaultNetworkType(
304                         mobileMappingsProxy.toIconKey(it.telephonyDisplayInfo.networkType)
305                     )
306                 } else {
307                     UnknownNetworkType
308                 }
309             }
310             .stateIn(scope, SharingStarted.WhileSubscribed(), UnknownNetworkType)
311 
312     override val inflateSignalStrength = systemUiCarrierConfig.shouldInflateSignalStrength
313     override val allowNetworkSliceIndicator = systemUiCarrierConfig.allowNetworkSliceIndicator
314 
315     override val numberOfLevels =
316         inflateSignalStrength
317             .map { shouldInflate ->
318                 if (shouldInflate) {
319                     DEFAULT_NUM_LEVELS + 1
320                 } else {
321                     DEFAULT_NUM_LEVELS
322                 }
323             }
324             .stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_NUM_LEVELS)
325 
326     override val carrierName =
327         subscriptionModel
328             .map {
329                 it?.let { model -> NetworkNameModel.SubscriptionDerived(model.carrierName) }
330                     ?: defaultNetworkName
331             }
332             .stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
333 
334     /**
335      * There are a few cases where we will need to poll [TelephonyManager] so we can update some
336      * internal state where callbacks aren't provided. Any of those events should be merged into
337      * this flow, which can be used to trigger the polling.
338      */
339     private val telephonyPollingEvent: Flow<Unit> = callbackEvents.map { Unit }
340 
341     override val cdmaRoaming: StateFlow<Boolean> =
342         telephonyPollingEvent
343             .mapLatest {
344                 try {
345                     val cdmaEri = telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber
346                     cdmaEri == ERI_ON || cdmaEri == ERI_FLASH
347                 } catch (e: UnsupportedOperationException) {
348                     // Handles the same as a function call failure
349                     false
350                 }
351             }
352             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
353 
354     override val carrierId =
355         broadcastDispatcher
356             .broadcastFlow(
357                 filter =
358                     IntentFilter(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED),
359                 map = { intent, _ -> intent },
360             )
361             .filter { intent ->
362                 intent.getIntExtra(EXTRA_SUBSCRIPTION_ID, INVALID_SUBSCRIPTION_ID) == subId
363             }
364             .map { it.carrierId() }
365             .onStart {
366                 // Make sure we get the initial carrierId
367                 emit(telephonyManager.simCarrierId)
368             }
369             .stateIn(scope, SharingStarted.WhileSubscribed(), telephonyManager.simCarrierId)
370 
371     /**
372      * BroadcastDispatcher does not handle sticky broadcasts, so we can't use it here. Note that we
373      * now use the [SharingStarted.Eagerly] strategy, because there have been cases where the sticky
374      * broadcast does not represent the correct state.
375      *
376      * See b/322432056 for context.
377      */
378     @SuppressLint("RegisterReceiverViaContext")
379     override val networkName: StateFlow<NetworkNameModel> =
380         conflatedCallbackFlow {
381                 val receiver =
382                     object : BroadcastReceiver() {
383                         override fun onReceive(context: Context, intent: Intent) {
384                             if (
385                                 intent.getIntExtra(
386                                     EXTRA_SUBSCRIPTION_INDEX,
387                                     INVALID_SUBSCRIPTION_ID
388                                 ) == subId
389                             ) {
390                                 logger.logServiceProvidersUpdatedBroadcast(intent)
391                                 trySend(
392                                     intent.toNetworkNameModel(networkNameSeparator)
393                                         ?: defaultNetworkName
394                                 )
395                             }
396                         }
397                     }
398 
399                 context.registerReceiver(
400                     receiver,
401                     IntentFilter(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED)
402                 )
403 
404                 awaitClose { context.unregisterReceiver(receiver) }
405             }
406             .flowOn(bgDispatcher)
407             .stateIn(scope, SharingStarted.Eagerly, defaultNetworkName)
408 
409     override val dataEnabled = run {
410         val initial = telephonyManager.isDataConnectionAllowed
411         callbackEvents
412             .mapNotNull { it.onDataEnabledChanged }
413             .map { it.enabled }
414             .stateIn(scope, SharingStarted.WhileSubscribed(), initial)
415     }
416 
417     override suspend fun isInEcmMode(): Boolean =
418         withContext(bgDispatcher) { telephonyManager.emergencyCallbackMode }
419 
420     /** Typical mobile connections aren't available during airplane mode. */
421     override val isAllowedDuringAirplaneMode = MutableStateFlow(false).asStateFlow()
422 
423     /**
424      * Currently, a network with NET_CAPABILITY_PRIORITIZE_LATENCY is the only type of network that
425      * we consider to be a "network slice". _PRIORITIZE_BANDWIDTH may be added in the future. Any of
426      * these capabilities that are used here must also be represented in the
427      * self_certified_network_capabilities.xml config file
428      */
429     @SuppressLint("WrongConstant")
430     private val networkSliceRequest =
431         NetworkRequest.Builder()
432             .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY)
433             .setSubscriptionIds(setOf(subId))
434             .build()
435 
436     @SuppressLint("MissingPermission")
437     override val hasPrioritizedNetworkCapabilities: StateFlow<Boolean> =
438         conflatedCallbackFlow {
439                 // Our network callback listens only for this.subId && net_cap_prioritize_latency
440                 // therefore our state is a simple mapping of whether or not that network exists
441                 val callback =
442                     object : NetworkCallback() {
443                         override fun onAvailable(network: Network) {
444                             logger.logPrioritizedNetworkAvailable(network.netId)
445                             trySend(true)
446                         }
447 
448                         override fun onLost(network: Network) {
449                             logger.logPrioritizedNetworkLost(network.netId)
450                             trySend(false)
451                         }
452                     }
453 
454                 connectivityManager.registerNetworkCallback(networkSliceRequest, callback)
455 
456                 awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
457             }
458             .flowOn(bgDispatcher)
459             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
460 
461     class Factory
462     @Inject
463     constructor(
464         private val context: Context,
465         private val broadcastDispatcher: BroadcastDispatcher,
466         private val connectivityManager: ConnectivityManager,
467         private val telephonyManager: TelephonyManager,
468         private val logger: MobileInputLogger,
469         private val carrierConfigRepository: CarrierConfigRepository,
470         private val mobileMappingsProxy: MobileMappingsProxy,
471         private val flags: FeatureFlagsClassic,
472         @Background private val bgDispatcher: CoroutineDispatcher,
473         @Application private val scope: CoroutineScope,
474     ) {
475         fun build(
476             subId: Int,
477             mobileLogger: TableLogBuffer,
478             subscriptionModel: Flow<SubscriptionModel?>,
479             defaultNetworkName: NetworkNameModel,
480             networkNameSeparator: String,
481         ): MobileConnectionRepository {
482             return MobileConnectionRepositoryImpl(
483                 subId,
484                 context,
485                 subscriptionModel,
486                 defaultNetworkName,
487                 networkNameSeparator,
488                 connectivityManager,
489                 telephonyManager.createForSubscriptionId(subId),
490                 carrierConfigRepository.getOrCreateConfigForSubId(subId),
491                 broadcastDispatcher,
492                 mobileMappingsProxy,
493                 bgDispatcher,
494                 logger,
495                 mobileLogger,
496                 flags,
497                 scope,
498             )
499         }
500     }
501 }
502 
Intentnull503 private fun Intent.carrierId(): Int =
504     getIntExtra(TelephonyManager.EXTRA_CARRIER_ID, UNKNOWN_CARRIER_ID)
505 
506 /**
507  * Wrap every [TelephonyCallback] we care about in a data class so we can accept them in a single
508  * shared flow and then split them back out into other flows.
509  */
510 sealed interface CallbackEvent {
511     data class OnCarrierNetworkChange(val active: Boolean) : CallbackEvent
512 
513     data class OnCarrierRoamingNtnModeChanged(val active: Boolean) : CallbackEvent
514 
515     data class OnDataActivity(val direction: Int) : CallbackEvent
516 
517     data class OnDataConnectionStateChanged(val dataState: Int) : CallbackEvent
518 
519     data class OnDataEnabledChanged(val enabled: Boolean) : CallbackEvent
520 
521     data class OnDisplayInfoChanged(val telephonyDisplayInfo: TelephonyDisplayInfo) : CallbackEvent
522 
523     data class OnServiceStateChanged(val serviceState: ServiceState) : CallbackEvent
524 
525     data class OnSignalStrengthChanged(val signalStrength: SignalStrength) : CallbackEvent
526 }
527 
528 /**
529  * A simple box type for 1-to-1 mapping of [CallbackEvent] to the batched event. Used in conjunction
530  * with [scan] to make sure we don't drop important callbacks due to late subscribers
531  */
532 data class TelephonyCallbackState(
533     val onDataActivity: CallbackEvent.OnDataActivity? = null,
534     val onCarrierNetworkChange: CallbackEvent.OnCarrierNetworkChange? = null,
535     val onCarrierRoamingNtnModeChanged: CallbackEvent.OnCarrierRoamingNtnModeChanged? = null,
536     val onDataConnectionStateChanged: CallbackEvent.OnDataConnectionStateChanged? = null,
537     val onDataEnabledChanged: CallbackEvent.OnDataEnabledChanged? = null,
538     val onDisplayInfoChanged: CallbackEvent.OnDisplayInfoChanged? = null,
539     val onServiceStateChanged: CallbackEvent.OnServiceStateChanged? = null,
540     val onSignalStrengthChanged: CallbackEvent.OnSignalStrengthChanged? = null,
541 ) {
applyEventnull542     fun applyEvent(event: CallbackEvent): TelephonyCallbackState {
543         return when (event) {
544             is CallbackEvent.OnCarrierNetworkChange -> copy(onCarrierNetworkChange = event)
545             is CallbackEvent.OnCarrierRoamingNtnModeChanged -> {
546                 copy(onCarrierRoamingNtnModeChanged = event)
547             }
548             is CallbackEvent.OnDataActivity -> copy(onDataActivity = event)
549             is CallbackEvent.OnDataConnectionStateChanged ->
550                 copy(onDataConnectionStateChanged = event)
551             is CallbackEvent.OnDataEnabledChanged -> copy(onDataEnabledChanged = event)
552             is CallbackEvent.OnDisplayInfoChanged -> copy(onDisplayInfoChanged = event)
553             is CallbackEvent.OnServiceStateChanged -> {
554                 copy(onServiceStateChanged = event)
555             }
556             is CallbackEvent.OnSignalStrengthChanged -> copy(onSignalStrengthChanged = event)
557         }
558     }
559 }
560