Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e03d1c36 authored by Evan Laird's avatar Evan Laird
Browse files

[mobile] split out CarrierConfigRepository interface for testing

Makes it easier to mock out in Kosmos. Then I went ahead and added it to
kosmos.

Bug: 364360986
Flag: EXEMPT refactor
Test: CarrierConfigRepositoryImplTest
Test: MobileConnectionsRepositoryTest
Test: all other sysui tests
Change-Id: I86caeb60e9036a202eced6f05ec69ad104c6aa45
parent 1a10e2da
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -269,7 +269,7 @@ filegroup {
        "tests/src/**/systemui/stylus/StylusManagerTest.kt",
        "tests/src/**/systemui/stylus/StylusManagerTest.kt",
        "tests/src/**/systemui/recents/OverviewProxyServiceTest.kt",
        "tests/src/**/systemui/recents/OverviewProxyServiceTest.kt",
        "tests/src/**/systemui/DisplayCutoutBaseViewTest.kt",
        "tests/src/**/systemui/DisplayCutoutBaseViewTest.kt",
        "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt",
        "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImplTest.kt",
        "tests/src/**/systemui/statusbar/policy/BatteryControllerTest.java",
        "tests/src/**/systemui/statusbar/policy/BatteryControllerTest.java",
        "tests/src/**/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt",
        "tests/src/**/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt",
        "tests/src/**/systemui/statusbar/KeyboardShortcutsReceiverTest.java",
        "tests/src/**/systemui/statusbar/KeyboardShortcutsReceiverTest.java",
+5 −0
Original line number Original line Diff line number Diff line
@@ -32,6 +32,8 @@ import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneMod
import com.android.systemui.statusbar.pipeline.icons.shared.BindableIconsRegistry
import com.android.systemui.statusbar.pipeline.icons.shared.BindableIconsRegistry
import com.android.systemui.statusbar.pipeline.icons.shared.BindableIconsRegistryImpl
import com.android.systemui.statusbar.pipeline.icons.shared.BindableIconsRegistryImpl
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigCoreStartable
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigCoreStartable
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepositoryImpl
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileRepositorySwitcher
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileRepositorySwitcher
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
@@ -119,6 +121,9 @@ abstract class StatusBarPipelineModule {


    @Binds abstract fun mobileMappingsProxy(impl: MobileMappingsProxyImpl): MobileMappingsProxy
    @Binds abstract fun mobileMappingsProxy(impl: MobileMappingsProxyImpl): MobileMappingsProxy


    @Binds
    abstract fun carrierConfigRepository(impl: CarrierConfigRepositoryImpl): CarrierConfigRepository

    @Binds
    @Binds
    abstract fun subscriptionManagerProxy(
    abstract fun subscriptionManagerProxy(
        impl: SubscriptionManagerProxyImpl
        impl: SubscriptionManagerProxyImpl
+4 −17
Original line number Original line Diff line number Diff line
@@ -48,11 +48,7 @@ import kotlinx.coroutines.flow.asStateFlow
 * 3. Add the new [BooleanCarrierConfig] to the list of tracked configs, so they are properly
 * 3. Add the new [BooleanCarrierConfig] to the list of tracked configs, so they are properly
 *    updated when a new carrier config comes down
 *    updated when a new carrier config comes down
 */
 */
class SystemUiCarrierConfig
class SystemUiCarrierConfig constructor(val subId: Int, defaultConfig: PersistableBundle) {
internal constructor(
    val subId: Int,
    defaultConfig: PersistableBundle,
) {
    @VisibleForTesting
    @VisibleForTesting
    var isUsingDefault = true
    var isUsingDefault = true
        private set
        private set
@@ -67,17 +63,11 @@ internal constructor(
    /** Flow tracking the [KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL] config */
    /** Flow tracking the [KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL] config */
    val showOperatorNameInStatusBar: StateFlow<Boolean> = showOperatorName.config
    val showOperatorNameInStatusBar: StateFlow<Boolean> = showOperatorName.config


    private val showNetworkSlice =
    private val showNetworkSlice = BooleanCarrierConfig(KEY_SHOW_5G_SLICE_ICON_BOOL, defaultConfig)
        BooleanCarrierConfig(KEY_SHOW_5G_SLICE_ICON_BOOL, defaultConfig)
    /** Flow tracking the [KEY_SHOW_5G_SLICE_ICON_BOOL] config */
    /** Flow tracking the [KEY_SHOW_5G_SLICE_ICON_BOOL] config */
    val allowNetworkSliceIndicator: StateFlow<Boolean> = showNetworkSlice.config
    val allowNetworkSliceIndicator: StateFlow<Boolean> = showNetworkSlice.config


    private val trackedConfigs =
    private val trackedConfigs = listOf(inflateSignalStrength, showOperatorName, showNetworkSlice)
        listOf(
            inflateSignalStrength,
            showOperatorName,
            showNetworkSlice,
        )


    /** Ingest a new carrier config, and switch all of the tracked keys over to the new values */
    /** Ingest a new carrier config, and switch all of the tracked keys over to the new values */
    fun processNewCarrierConfig(config: PersistableBundle) {
    fun processNewCarrierConfig(config: PersistableBundle) {
@@ -98,10 +88,7 @@ internal constructor(
}
}


/** Extracts [key] from the carrier config, and stores it in a flow */
/** Extracts [key] from the carrier config, and stores it in a flow */
private class BooleanCarrierConfig(
private class BooleanCarrierConfig(val key: String, defaultConfig: PersistableBundle) {
    val key: String,
    defaultConfig: PersistableBundle,
) {
    private val _configValue = MutableStateFlow(defaultConfig.getBoolean(key))
    private val _configValue = MutableStateFlow(defaultConfig.getBoolean(key))
    val config = _configValue.asStateFlow()
    val config = _configValue.asStateFlow()


+3 −100
Original line number Original line Diff line number Diff line
@@ -16,31 +16,8 @@


package com.android.systemui.statusbar.pipeline.mobile.data.repository
package com.android.systemui.statusbar.pipeline.mobile.data.repository


import android.content.IntentFilter
import android.os.PersistableBundle
import android.telephony.CarrierConfigManager
import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionManager
import android.util.SparseArray
import androidx.annotation.VisibleForTesting
import androidx.core.util.getOrElse
import androidx.core.util.isEmpty
import androidx.core.util.keyIterator
import com.android.systemui.Dumpable
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.shareIn


/**
/**
 * Meant to be the source of truth regarding CarrierConfigs. These are configuration objects defined
 * Meant to be the source of truth regarding CarrierConfigs. These are configuration objects defined
@@ -50,87 +27,13 @@ import kotlinx.coroutines.flow.shareIn
 *
 *
 * See [SystemUiCarrierConfig] for details on how to add carrier config keys to be tracked
 * See [SystemUiCarrierConfig] for details on how to add carrier config keys to be tracked
 */
 */
@SysUISingleton
interface CarrierConfigRepository {
class CarrierConfigRepository
@Inject
constructor(
    broadcastDispatcher: BroadcastDispatcher,
    private val carrierConfigManager: CarrierConfigManager?,
    dumpManager: DumpManager,
    logger: MobileInputLogger,
    @Application scope: CoroutineScope,
) : Dumpable {
    private var isListening = false
    private val defaultConfig: PersistableBundle by lazy { CarrierConfigManager.getDefaultConfig() }
    // Used for logging the default config in the dumpsys
    private val defaultConfigForLogs: SystemUiCarrierConfig by lazy {
        SystemUiCarrierConfig(-1, defaultConfig)
    }

    private val configs = SparseArray<SystemUiCarrierConfig>()

    init {
        dumpManager.registerNormalDumpable(this)
    }

    @VisibleForTesting
    val carrierConfigStream: SharedFlow<Pair<Int, PersistableBundle>> =
        broadcastDispatcher
            .broadcastFlow(IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
                intent,
                _ ->
                intent.getIntExtra(
                    CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
                    SubscriptionManager.INVALID_SUBSCRIPTION_ID
                )
            }
            .onEach { logger.logCarrierConfigChanged(it) }
            .filter { SubscriptionManager.isValidSubscriptionId(it) }
            .mapNotNull { subId ->
                val config = carrierConfigManager?.getConfigForSubId(subId)
                config?.let { subId to it }
            }
            .shareIn(scope, SharingStarted.WhileSubscribed())

    /**
    /**
     * Start this repository observing broadcasts for **all** carrier configuration updates. Must be
     * Start this repository observing broadcasts for **all** carrier configuration updates. Must be
     * called in order to keep SystemUI in sync with [CarrierConfigManager].
     * called in order to keep SystemUI in sync with [CarrierConfigManager].
     */
     */
    suspend fun startObservingCarrierConfigUpdates() {
    suspend fun startObservingCarrierConfigUpdates()
        isListening = true
        carrierConfigStream.collect { updateCarrierConfig(it.first, it.second) }
    }

    /** Update or create the [SystemUiCarrierConfig] for subId with the override */
    private fun updateCarrierConfig(subId: Int, config: PersistableBundle) {
        val configToUpdate = getOrCreateConfigForSubId(subId)
        configToUpdate.processNewCarrierConfig(config)
    }


    /** Gets a cached [SystemUiCarrierConfig], or creates a new one which will track the defaults */
    /** Gets a cached [SystemUiCarrierConfig], or creates a new one which will track the defaults */
    fun getOrCreateConfigForSubId(subId: Int): SystemUiCarrierConfig {
    fun getOrCreateConfigForSubId(subId: Int): SystemUiCarrierConfig
        return configs.getOrElse(subId) {
            val config = SystemUiCarrierConfig(subId, defaultConfig)
            val carrierConfig = carrierConfigManager?.getConfigForSubId(subId)
            if (carrierConfig != null) config.processNewCarrierConfig(carrierConfig)
            configs.put(subId, config)
            config
        }
    }

    override fun dump(pw: PrintWriter, args: Array<out String>) {
        pw.println("isListening: $isListening")
        if (configs.isEmpty()) {
            pw.println("no carrier configs loaded")
        } else {
            pw.println("Carrier configs by subId")
            configs.keyIterator().forEach {
                pw.println("  subId=$it")
                pw.println("    config=${configs.get(it).toStringConsideringDefaults()}")
            }
            // Finally, print the default config
            pw.println("Default config:")
            pw.println("  $defaultConfigForLogs")
        }
    }
}
}
+120 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.statusbar.pipeline.mobile.data.repository

import android.content.IntentFilter
import android.os.PersistableBundle
import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionManager
import android.util.SparseArray
import androidx.annotation.VisibleForTesting
import androidx.core.util.getOrElse
import androidx.core.util.isEmpty
import androidx.core.util.keyIterator
import com.android.systemui.Dumpable
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.onEach

@SysUISingleton
class CarrierConfigRepositoryImpl
@Inject
constructor(
    broadcastDispatcher: BroadcastDispatcher,
    private val carrierConfigManager: CarrierConfigManager?,
    dumpManager: DumpManager,
    logger: MobileInputLogger,
    @Application scope: CoroutineScope,
) : CarrierConfigRepository, Dumpable {
    private var isListening = false
    private val defaultConfig: PersistableBundle by lazy { CarrierConfigManager.getDefaultConfig() }
    // Used for logging the default config in the dumpsys
    private val defaultConfigForLogs: SystemUiCarrierConfig by lazy {
        SystemUiCarrierConfig(-1, defaultConfig)
    }

    private val configs = SparseArray<SystemUiCarrierConfig>()

    init {
        dumpManager.registerNormalDumpable(this)
    }

    @VisibleForTesting
    val carrierConfigStream: Flow<Pair<Int, PersistableBundle>> =
        broadcastDispatcher
            .broadcastFlow(IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
                intent,
                _ ->
                intent.getIntExtra(
                    CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
                    SubscriptionManager.INVALID_SUBSCRIPTION_ID,
                )
            }
            .onEach { logger.logCarrierConfigChanged(it) }
            .filter { SubscriptionManager.isValidSubscriptionId(it) }
            .mapNotNull { subId ->
                val config = carrierConfigManager?.getConfigForSubId(subId)
                config?.let { subId to it }
            }

    override suspend fun startObservingCarrierConfigUpdates() {
        isListening = true
        carrierConfigStream.collect { updateCarrierConfig(it.first, it.second) }
    }

    /** Update or create the [SystemUiCarrierConfig] for subId with the override */
    private fun updateCarrierConfig(subId: Int, config: PersistableBundle) {
        val configToUpdate = getOrCreateConfigForSubId(subId)
        configToUpdate.processNewCarrierConfig(config)
    }

    override fun getOrCreateConfigForSubId(subId: Int): SystemUiCarrierConfig {
        return configs.getOrElse(subId) {
            val config = SystemUiCarrierConfig(subId, defaultConfig)
            val carrierConfig = carrierConfigManager?.getConfigForSubId(subId)
            if (carrierConfig != null) config.processNewCarrierConfig(carrierConfig)
            configs.put(subId, config)
            config
        }
    }

    override fun dump(pw: PrintWriter, args: Array<out String>) {
        pw.println("isListening: $isListening")
        if (configs.isEmpty()) {
            pw.println("no carrier configs loaded")
        } else {
            pw.println("Carrier configs by subId")
            configs.keyIterator().forEach {
                pw.println("  subId=$it")
                pw.println("    config=${configs.get(it).toStringConsideringDefaults()}")
            }
            // Finally, print the default config
            pw.println("Default config:")
            pw.println("  $defaultConfigForLogs")
        }
    }
}
Loading