1 /* <lambda>null2 * 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.repository 18 19 import android.content.IntentFilter 20 import android.os.PersistableBundle 21 import android.telephony.CarrierConfigManager 22 import android.telephony.SubscriptionManager 23 import android.util.SparseArray 24 import androidx.annotation.VisibleForTesting 25 import androidx.core.util.getOrElse 26 import androidx.core.util.isEmpty 27 import androidx.core.util.keyIterator 28 import com.android.systemui.Dumpable 29 import com.android.systemui.broadcast.BroadcastDispatcher 30 import com.android.systemui.dagger.SysUISingleton 31 import com.android.systemui.dagger.qualifiers.Application 32 import com.android.systemui.dump.DumpManager 33 import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger 34 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig 35 import java.io.PrintWriter 36 import javax.inject.Inject 37 import kotlinx.coroutines.CoroutineScope 38 import kotlinx.coroutines.flow.SharedFlow 39 import kotlinx.coroutines.flow.SharingStarted 40 import kotlinx.coroutines.flow.filter 41 import kotlinx.coroutines.flow.mapNotNull 42 import kotlinx.coroutines.flow.onEach 43 import kotlinx.coroutines.flow.shareIn 44 45 /** 46 * Meant to be the source of truth regarding CarrierConfigs. These are configuration objects defined 47 * on a per-subscriptionId basis, and do not trigger a device configuration event. 48 * 49 * Designed to supplant [com.android.systemui.util.CarrierConfigTracker]. 50 * 51 * See [SystemUiCarrierConfig] for details on how to add carrier config keys to be tracked 52 */ 53 @SysUISingleton 54 class CarrierConfigRepository 55 @Inject 56 constructor( 57 broadcastDispatcher: BroadcastDispatcher, 58 private val carrierConfigManager: CarrierConfigManager?, 59 dumpManager: DumpManager, 60 logger: MobileInputLogger, 61 @Application scope: CoroutineScope, 62 ) : Dumpable { 63 private var isListening = false 64 private val defaultConfig: PersistableBundle by lazy { CarrierConfigManager.getDefaultConfig() } 65 // Used for logging the default config in the dumpsys 66 private val defaultConfigForLogs: SystemUiCarrierConfig by lazy { 67 SystemUiCarrierConfig(-1, defaultConfig) 68 } 69 70 private val configs = SparseArray<SystemUiCarrierConfig>() 71 72 init { 73 dumpManager.registerNormalDumpable(this) 74 } 75 76 @VisibleForTesting 77 val carrierConfigStream: SharedFlow<Pair<Int, PersistableBundle>> = 78 broadcastDispatcher 79 .broadcastFlow(IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { 80 intent, 81 _ -> 82 intent.getIntExtra( 83 CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, 84 SubscriptionManager.INVALID_SUBSCRIPTION_ID 85 ) 86 } 87 .onEach { logger.logCarrierConfigChanged(it) } 88 .filter { SubscriptionManager.isValidSubscriptionId(it) } 89 .mapNotNull { subId -> 90 val config = carrierConfigManager?.getConfigForSubId(subId) 91 config?.let { subId to it } 92 } 93 .shareIn(scope, SharingStarted.WhileSubscribed()) 94 95 /** 96 * Start this repository observing broadcasts for **all** carrier configuration updates. Must be 97 * called in order to keep SystemUI in sync with [CarrierConfigManager]. 98 */ 99 suspend fun startObservingCarrierConfigUpdates() { 100 isListening = true 101 carrierConfigStream.collect { updateCarrierConfig(it.first, it.second) } 102 } 103 104 /** Update or create the [SystemUiCarrierConfig] for subId with the override */ 105 private fun updateCarrierConfig(subId: Int, config: PersistableBundle) { 106 val configToUpdate = getOrCreateConfigForSubId(subId) 107 configToUpdate.processNewCarrierConfig(config) 108 } 109 110 /** Gets a cached [SystemUiCarrierConfig], or creates a new one which will track the defaults */ 111 fun getOrCreateConfigForSubId(subId: Int): SystemUiCarrierConfig { 112 return configs.getOrElse(subId) { 113 val config = SystemUiCarrierConfig(subId, defaultConfig) 114 val carrierConfig = carrierConfigManager?.getConfigForSubId(subId) 115 if (carrierConfig != null) config.processNewCarrierConfig(carrierConfig) 116 configs.put(subId, config) 117 config 118 } 119 } 120 121 override fun dump(pw: PrintWriter, args: Array<out String>) { 122 pw.println("isListening: $isListening") 123 if (configs.isEmpty()) { 124 pw.println("no carrier configs loaded") 125 } else { 126 pw.println("Carrier configs by subId") 127 configs.keyIterator().forEach { 128 pw.println(" subId=$it") 129 pw.println(" config=${configs.get(it).toStringConsideringDefaults()}") 130 } 131 // Finally, print the default config 132 pw.println("Default config:") 133 pw.println(" $defaultConfigForLogs") 134 } 135 } 136 } 137