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