1 /*
2  * Copyright (C) 2023 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.model
18 
19 import android.os.PersistableBundle
20 import android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL
21 import android.telephony.CarrierConfigManager.KEY_SHOW_5G_SLICE_ICON_BOOL
22 import android.telephony.CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL
23 import androidx.annotation.VisibleForTesting
24 import kotlinx.coroutines.flow.MutableStateFlow
25 import kotlinx.coroutines.flow.StateFlow
26 import kotlinx.coroutines.flow.asStateFlow
27 
28 /**
29  * Represents, for a given subscription ID, the set of keys about which SystemUI cares.
30  *
31  * Upon first creation, this config represents only the default configuration (see
32  * [android.telephony.CarrierConfigManager.getDefaultConfig]).
33  *
34  * Upon request (see
35  * [com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository]), an
36  * instance of this class may be created for a given subscription Id, and will default to
37  * representing the default carrier configuration. However, once a carrier config is received for
38  * this [subId], all fields will reflect those in the received config, using [PersistableBundle]'s
39  * default of false for any config that is not present in the override.
40  *
41  * To keep things relatively simple, this class defines a wrapper around each config key which
42  * exposes a StateFlow<Boolean> for each config we care about. It also tracks whether or not it is
43  * using the default config for logging purposes.
44  *
45  * NOTE to add new keys to be tracked:
46  * 1. Define a new `private val` wrapping the key using [BooleanCarrierConfig]
47  * 2. Define a public `val` exposing the wrapped flow using [BooleanCarrierConfig.config]
48  * 3. Add the new [BooleanCarrierConfig] to the list of tracked configs, so they are properly
49  *    updated when a new carrier config comes down
50  */
51 class SystemUiCarrierConfig
52 internal constructor(
53     val subId: Int,
54     defaultConfig: PersistableBundle,
55 ) {
56     @VisibleForTesting
57     var isUsingDefault = true
58         private set
59 
60     private val inflateSignalStrength =
61         BooleanCarrierConfig(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, defaultConfig)
62     /** Flow tracking the [KEY_INFLATE_SIGNAL_STRENGTH_BOOL] carrier config */
63     val shouldInflateSignalStrength: StateFlow<Boolean> = inflateSignalStrength.config
64 
65     private val showOperatorName =
66         BooleanCarrierConfig(KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL, defaultConfig)
67     /** Flow tracking the [KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL] config */
68     val showOperatorNameInStatusBar: StateFlow<Boolean> = showOperatorName.config
69 
70     private val showNetworkSlice =
71         BooleanCarrierConfig(KEY_SHOW_5G_SLICE_ICON_BOOL, defaultConfig)
72     /** Flow tracking the [KEY_SHOW_5G_SLICE_ICON_BOOL] config */
73     val allowNetworkSliceIndicator: StateFlow<Boolean> = showNetworkSlice.config
74 
75     private val trackedConfigs =
76         listOf(
77             inflateSignalStrength,
78             showOperatorName,
79             showNetworkSlice,
80         )
81 
82     /** Ingest a new carrier config, and switch all of the tracked keys over to the new values */
processNewCarrierConfignull83     fun processNewCarrierConfig(config: PersistableBundle) {
84         isUsingDefault = false
85         trackedConfigs.forEach { it.update(config) }
86     }
87 
88     /** For dumpsys, shortcut if we haven't overridden any keys */
toStringConsideringDefaultsnull89     fun toStringConsideringDefaults(): String {
90         return if (isUsingDefault) {
91             "using defaults"
92         } else {
93             trackedConfigs.joinToString { it.toString() }
94         }
95     }
96 
<lambda>null97     override fun toString(): String = trackedConfigs.joinToString { it.toString() }
98 }
99 
100 /** Extracts [key] from the carrier config, and stores it in a flow */
101 private class BooleanCarrierConfig(
102     val key: String,
103     defaultConfig: PersistableBundle,
104 ) {
105     private val _configValue = MutableStateFlow(defaultConfig.getBoolean(key))
106     val config = _configValue.asStateFlow()
107 
updatenull108     fun update(config: PersistableBundle) {
109         _configValue.value = config.getBoolean(key)
110     }
111 
toStringnull112     override fun toString(): String {
113         return "$key=${config.value}"
114     }
115 }
116