[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
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 3d250fd..a91e1ed 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -269,7 +269,7 @@
"tests/src/**/systemui/stylus/StylusManagerTest.kt",
"tests/src/**/systemui/recents/OverviewProxyServiceTest.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/SensitiveNotificationProtectionControllerTest.kt",
"tests/src/**/systemui/statusbar/KeyboardShortcutsReceiverTest.java",
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index bfdc8bd..a88b74c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -32,6 +32,8 @@
import com.android.systemui.statusbar.pipeline.icons.shared.BindableIconsRegistry
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.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.MobileRepositorySwitcher
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
@@ -120,6 +122,9 @@
@Binds abstract fun mobileMappingsProxy(impl: MobileMappingsProxyImpl): MobileMappingsProxy
@Binds
+ abstract fun carrierConfigRepository(impl: CarrierConfigRepositoryImpl): CarrierConfigRepository
+
+ @Binds
abstract fun subscriptionManagerProxy(
impl: SubscriptionManagerProxyImpl
): SubscriptionManagerProxy
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt
index 0871c86..5f33a754 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfig.kt
@@ -48,11 +48,7 @@
* 3. Add the new [BooleanCarrierConfig] to the list of tracked configs, so they are properly
* updated when a new carrier config comes down
*/
-class SystemUiCarrierConfig
-internal constructor(
- val subId: Int,
- defaultConfig: PersistableBundle,
-) {
+class SystemUiCarrierConfig constructor(val subId: Int, defaultConfig: PersistableBundle) {
@VisibleForTesting
var isUsingDefault = true
private set
@@ -67,17 +63,11 @@
/** Flow tracking the [KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL] config */
val showOperatorNameInStatusBar: StateFlow<Boolean> = showOperatorName.config
- private val showNetworkSlice =
- BooleanCarrierConfig(KEY_SHOW_5G_SLICE_ICON_BOOL, defaultConfig)
+ private val showNetworkSlice = BooleanCarrierConfig(KEY_SHOW_5G_SLICE_ICON_BOOL, defaultConfig)
/** Flow tracking the [KEY_SHOW_5G_SLICE_ICON_BOOL] config */
val allowNetworkSliceIndicator: StateFlow<Boolean> = showNetworkSlice.config
- private val trackedConfigs =
- listOf(
- inflateSignalStrength,
- showOperatorName,
- showNetworkSlice,
- )
+ private val trackedConfigs = listOf(inflateSignalStrength, showOperatorName, showNetworkSlice)
/** Ingest a new carrier config, and switch all of the tracked keys over to the new values */
fun processNewCarrierConfig(config: PersistableBundle) {
@@ -98,10 +88,7 @@
}
/** Extracts [key] from the carrier config, and stores it in a flow */
-private class BooleanCarrierConfig(
- val key: String,
- defaultConfig: PersistableBundle,
-) {
+private class BooleanCarrierConfig(val key: String, defaultConfig: PersistableBundle) {
private val _configValue = MutableStateFlow(defaultConfig.getBoolean(key))
val config = _configValue.asStateFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
index 016ba5f..30c529a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepository.kt
@@ -16,31 +16,8 @@
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.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
@@ -50,87 +27,13 @@
*
* See [SystemUiCarrierConfig] for details on how to add carrier config keys to be tracked
*/
-@SysUISingleton
-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())
-
+interface CarrierConfigRepository {
/**
* Start this repository observing broadcasts for **all** carrier configuration updates. Must be
* called in order to keep SystemUI in sync with [CarrierConfigManager].
*/
- 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)
- }
+ suspend fun startObservingCarrierConfigUpdates()
/** Gets a cached [SystemUiCarrierConfig], or creates a new one which will track the defaults */
- 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")
- }
- }
+ fun getOrCreateConfigForSubId(subId: Int): SystemUiCarrierConfig
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImpl.kt
new file mode 100644
index 0000000..7ed6b05
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImpl.kt
@@ -0,0 +1,120 @@
+/*
+ * 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")
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImplTest.kt
similarity index 96%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImplTest.kt
index 320c148..34e06d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImplTest.kt
@@ -48,11 +48,11 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
-class CarrierConfigRepositoryTest : SysuiTestCase() {
+class CarrierConfigRepositoryImplTest : SysuiTestCase() {
private val testDispatcher = UnconfinedTestDispatcher()
private val testScope = TestScope(testDispatcher)
- private lateinit var underTest: CarrierConfigRepository
+ private lateinit var underTest: CarrierConfigRepositoryImpl
private lateinit var mockitoSession: MockitoSession
private lateinit var carrierConfigCoreStartable: CarrierConfigCoreStartable
@@ -81,7 +81,7 @@
}
underTest =
- CarrierConfigRepository(
+ CarrierConfigRepositoryImpl(
fakeBroadcastDispatcher,
carrierConfigManager,
dumpManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 2e0b7c6..d7456df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -58,6 +58,7 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.carrierConfigRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.tableBufferLogName
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.mobile.util.FakeSubscriptionManagerProxy
@@ -68,7 +69,6 @@
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.fakeUserRepository
-import com.android.systemui.user.data.repository.userRepository
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
@@ -209,14 +209,7 @@
wifiTableLogBuffer,
)
- carrierConfigRepository =
- CarrierConfigRepository(
- fakeBroadcastDispatcher,
- mock(),
- mock(),
- logger,
- testScope.backgroundScope,
- )
+ carrierConfigRepository = kosmos.carrierConfigRepository
connectionFactory =
MobileConnectionRepositoryImpl.Factory(
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryKosmos.kt
new file mode 100644
index 0000000..a6431af
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryKosmos.kt
@@ -0,0 +1,24 @@
+/*
+ * 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 com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.carrierConfigRepository: CarrierConfigRepository by Fixture {
+ FakeCarrierConfigRepository()
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeCarrierConfigRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeCarrierConfigRepository.kt
new file mode 100644
index 0000000..e0ac9c8
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeCarrierConfigRepository.kt
@@ -0,0 +1,52 @@
+/*
+ * 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.os.PersistableBundle
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
+
+class FakeCarrierConfigRepository : CarrierConfigRepository {
+ override suspend fun startObservingCarrierConfigUpdates() {}
+
+ val configsById = mutableMapOf<Int, SystemUiCarrierConfig>()
+
+ override fun getOrCreateConfigForSubId(subId: Int): SystemUiCarrierConfig =
+ configsById.getOrPut(subId) { SystemUiCarrierConfig(subId, createDefaultTestConfig()) }
+}
+
+fun createDefaultTestConfig() =
+ PersistableBundle().also {
+ it.putBoolean(
+ android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL,
+ false,
+ )
+ it.putBoolean(
+ android.telephony.CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL,
+ false,
+ )
+ it.putBoolean(android.telephony.CarrierConfigManager.KEY_SHOW_5G_SLICE_ICON_BOOL, true)
+ }
+
+/** Override the default config with the given (key, value) pair */
+fun configWithOverride(key: String, override: Boolean): PersistableBundle =
+ createDefaultTestConfig().also { it.putBoolean(key, override) }
+
+/** Override any number of configs from the default */
+fun configWithOverrides(vararg overrides: Pair<String, Boolean>) =
+ createDefaultTestConfig().also { config ->
+ overrides.forEach { (key, value) -> config.putBoolean(key, value) }
+ }