[kairos] Fork status bar mobile data layer

Flag: com.android.systemui.status_bar_mobile_icon_kairos
Bug: 383172066
Test: atest
Change-Id: Ieb8eb523b8737600b288d843cdffbe7e00adc572
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherKairosTest.kt
new file mode 100644
index 0000000..f82de7a
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherKairosTest.kt
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2025 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.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
+import android.telephony.TelephonyManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.demomode.DemoMode
+import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.tableLogBufferFactory
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoModeMobileConnectionDataSource
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.validMobileEvent
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeSubscriptionManagerProxy
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.kotlinArgumentCaptor
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+/**
+ * The switcher acts as a dispatcher to either the `prod` or `demo` versions of the repository
+ * interface it's switching on. These tests just need to verify that the entire interface properly
+ * switches over when the value of `demoMode` changes
+ */
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MobileRepositorySwitcherKairosTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    private lateinit var underTest: MobileRepositorySwitcherKairos
+    private lateinit var realRepo: MobileConnectionsRepositoryImpl
+    private lateinit var demoRepo: DemoMobileConnectionsRepository
+    private lateinit var mobileDataSource: DemoModeMobileConnectionDataSource
+    private lateinit var wifiDataSource: DemoModeWifiDataSource
+    private lateinit var wifiRepository: FakeWifiRepository
+    private lateinit var connectivityRepository: ConnectivityRepository
+
+    @Mock private lateinit var subscriptionManager: SubscriptionManager
+    @Mock private lateinit var telephonyManager: TelephonyManager
+    @Mock private lateinit var logger: MobileInputLogger
+    @Mock private lateinit var summaryLogger: TableLogBuffer
+    @Mock private lateinit var demoModeController: DemoModeController
+    @Mock private lateinit var dumpManager: DumpManager
+
+    private val fakeNetworkEventsFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
+    private val mobileMappings = FakeMobileMappingsProxy()
+    private val subscriptionManagerProxy = FakeSubscriptionManagerProxy()
+
+    private val scope = CoroutineScope(IMMEDIATE)
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        // Never start in demo mode
+        whenever(demoModeController.isInDemoMode).thenReturn(false)
+
+        mobileDataSource =
+            mock<DemoModeMobileConnectionDataSource>().also {
+                whenever(it.mobileEvents).thenReturn(fakeNetworkEventsFlow)
+            }
+        wifiDataSource =
+            mock<DemoModeWifiDataSource>().also {
+                whenever(it.wifiEvents).thenReturn(MutableStateFlow(null))
+            }
+        wifiRepository = FakeWifiRepository()
+
+        connectivityRepository = FakeConnectivityRepository()
+
+        realRepo =
+            MobileConnectionsRepositoryImpl(
+                connectivityRepository,
+                subscriptionManager,
+                subscriptionManagerProxy,
+                telephonyManager,
+                logger,
+                summaryLogger,
+                mobileMappings,
+                fakeBroadcastDispatcher,
+                context,
+                /* bgDispatcher = */ IMMEDIATE,
+                scope,
+                /* mainDispatcher = */ IMMEDIATE,
+                FakeAirplaneModeRepository(),
+                wifiRepository,
+                mock(),
+                mock(),
+                mock(),
+            )
+
+        demoRepo =
+            DemoMobileConnectionsRepository(
+                mobileDataSource = mobileDataSource,
+                wifiDataSource = wifiDataSource,
+                scope = scope,
+                context = context,
+                logFactory = kosmos.tableLogBufferFactory,
+            )
+
+        underTest =
+            MobileRepositorySwitcherKairos(
+                scope = scope,
+                realRepository = realRepo,
+                demoMobileConnectionsRepository = demoRepo,
+                demoModeController = demoModeController,
+            )
+    }
+
+    @After
+    fun tearDown() {
+        scope.cancel()
+    }
+
+    @Test
+    fun activeRepoMatchesDemoModeSetting() =
+        runBlocking(IMMEDIATE) {
+            whenever(demoModeController.isInDemoMode).thenReturn(false)
+
+            var latest: MobileConnectionsRepository? = null
+            val job = underTest.activeRepo.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(realRepo)
+
+            startDemoMode()
+
+            assertThat(latest).isEqualTo(demoRepo)
+
+            finishDemoMode()
+
+            assertThat(latest).isEqualTo(realRepo)
+
+            job.cancel()
+        }
+
+    @Test
+    fun subscriptionListUpdatesWhenDemoModeChanges() =
+        runBlocking(IMMEDIATE) {
+            whenever(demoModeController.isInDemoMode).thenReturn(false)
+
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1, SUB_2))
+
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+            // The real subscriptions has 2 subs
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1, SUB_2))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            assertThat(latest).isEqualTo(listOf(MODEL_1, MODEL_2))
+
+            // Demo mode turns on, and we should see only the demo subscriptions
+            startDemoMode()
+            fakeNetworkEventsFlow.value = validMobileEvent(subId = 3)
+
+            // Demo mobile connections repository makes arbitrarily-formed subscription info
+            // objects, so just validate the data we care about
+            assertThat(latest).hasSize(1)
+            assertThat(latest!![0].subscriptionId).isEqualTo(3)
+
+            finishDemoMode()
+
+            assertThat(latest).isEqualTo(listOf(MODEL_1, MODEL_2))
+
+            job.cancel()
+        }
+
+    private fun startDemoMode() {
+        whenever(demoModeController.isInDemoMode).thenReturn(true)
+        getDemoModeCallback().onDemoModeStarted()
+    }
+
+    private fun finishDemoMode() {
+        whenever(demoModeController.isInDemoMode).thenReturn(false)
+        getDemoModeCallback().onDemoModeFinished()
+    }
+
+    private fun getSubscriptionCallback(): SubscriptionManager.OnSubscriptionsChangedListener {
+        val callbackCaptor =
+            kotlinArgumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener>()
+        verify(subscriptionManager)
+            .addOnSubscriptionsChangedListener(any(), callbackCaptor.capture())
+        return callbackCaptor.value
+    }
+
+    private fun getDemoModeCallback(): DemoMode {
+        val captor = kotlinArgumentCaptor<DemoMode>()
+        verify(demoModeController).addCallback(captor.capture())
+        return captor.value
+    }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+
+        private const val SUB_1_ID = 1
+        private const val SUB_1_NAME = "Carrier $SUB_1_ID"
+        private val SUB_1 =
+            mock<SubscriptionInfo>().also {
+                whenever(it.subscriptionId).thenReturn(SUB_1_ID)
+                whenever(it.carrierName).thenReturn(SUB_1_NAME)
+                whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
+            }
+        private val MODEL_1 =
+            SubscriptionModel(
+                subscriptionId = SUB_1_ID,
+                carrierName = SUB_1_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+
+        private const val SUB_2_ID = 2
+        private const val SUB_2_NAME = "Carrier $SUB_2_ID"
+        private val SUB_2 =
+            mock<SubscriptionInfo>().also {
+                whenever(it.subscriptionId).thenReturn(SUB_2_ID)
+                whenever(it.carrierName).thenReturn(SUB_2_NAME)
+                whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
+            }
+        private val MODEL_2 =
+            SubscriptionModel(
+                subscriptionId = SUB_2_ID,
+                carrierName = SUB_2_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionKairosParameterizedTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionKairosParameterizedTest.kt
new file mode 100644
index 0000000..d2cd227
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionKairosParameterizedTest.kt
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2022 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.demo
+
+import android.telephony.Annotation
+import android.telephony.TelephonyManager
+import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
+import androidx.test.filters.SmallTest
+import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.table.tableLogBufferFactory
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
+import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
+
+/**
+ * Parameterized test for all of the common values of [FakeNetworkEventModel]. This test simply
+ * verifies that passing the given model to [DemoMobileConnectionsRepository] results in the correct
+ * flows emitting from the given connection.
+ */
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(ParameterizedAndroidJunit4::class)
+internal class DemoMobileConnectionKairosParameterizedTest(private val testCase: TestCase) :
+    SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    private val testDispatcher = UnconfinedTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+
+    private val fakeNetworkEventFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
+    private val fakeWifiEventFlow = MutableStateFlow<FakeWifiEventModel?>(null)
+
+    private lateinit var connectionsRepo: DemoMobileConnectionsRepositoryKairos
+    private lateinit var underTest: DemoMobileConnectionRepository
+    private lateinit var mockDataSource: DemoModeMobileConnectionDataSource
+    private lateinit var mockWifiDataSource: DemoModeWifiDataSource
+
+    @Before
+    fun setUp() {
+        // The data source only provides one API, so we can mock it with a flow here for convenience
+        mockDataSource =
+            mock<DemoModeMobileConnectionDataSource>().also {
+                whenever(it.mobileEvents).thenReturn(fakeNetworkEventFlow)
+            }
+        mockWifiDataSource =
+            mock<DemoModeWifiDataSource>().also {
+                whenever(it.wifiEvents).thenReturn(fakeWifiEventFlow)
+            }
+
+        connectionsRepo =
+            DemoMobileConnectionsRepositoryKairos(
+                mobileDataSource = mockDataSource,
+                wifiDataSource = mockWifiDataSource,
+                scope = testScope.backgroundScope,
+                context = context,
+                logFactory = kosmos.tableLogBufferFactory,
+            )
+
+        connectionsRepo.startProcessingCommands()
+    }
+
+    @After
+    fun tearDown() {
+        testScope.cancel()
+    }
+
+    @Test
+    fun demoNetworkData() =
+        testScope.runTest {
+            val networkModel =
+                FakeNetworkEventModel.Mobile(
+                    level = testCase.level,
+                    dataType = testCase.dataType,
+                    subId = testCase.subId,
+                    carrierId = testCase.carrierId,
+                    inflateStrength = testCase.inflateStrength,
+                    activity = testCase.activity,
+                    carrierNetworkChange = testCase.carrierNetworkChange,
+                    roaming = testCase.roaming,
+                    name = "demo name",
+                    slice = testCase.slice,
+                )
+
+            fakeNetworkEventFlow.value = networkModel
+            underTest = connectionsRepo.getRepoForSubId(subId)
+
+            assertConnection(underTest, networkModel)
+        }
+
+    private fun TestScope.startCollection(conn: DemoMobileConnectionRepository): Job {
+        val job = launch {
+            launch { conn.cdmaLevel.collect {} }
+            launch { conn.primaryLevel.collect {} }
+            launch { conn.dataActivityDirection.collect {} }
+            launch { conn.carrierNetworkChangeActive.collect {} }
+            launch { conn.isRoaming.collect {} }
+            launch { conn.networkName.collect {} }
+            launch { conn.carrierName.collect {} }
+            launch { conn.isEmergencyOnly.collect {} }
+            launch { conn.dataConnectionState.collect {} }
+            launch { conn.hasPrioritizedNetworkCapabilities.collect {} }
+        }
+        return job
+    }
+
+    private fun TestScope.assertConnection(
+        conn: DemoMobileConnectionRepository,
+        model: FakeNetworkEventModel,
+    ) {
+        val job = startCollection(underTest)
+        when (model) {
+            is FakeNetworkEventModel.Mobile -> {
+                assertThat(conn.subId).isEqualTo(model.subId)
+                assertThat(conn.cdmaLevel.value).isEqualTo(model.level)
+                assertThat(conn.primaryLevel.value).isEqualTo(model.level)
+                assertThat(conn.dataActivityDirection.value)
+                    .isEqualTo((model.activity ?: DATA_ACTIVITY_NONE).toMobileDataActivityModel())
+                assertThat(conn.carrierNetworkChangeActive.value)
+                    .isEqualTo(model.carrierNetworkChange)
+                assertThat(conn.isRoaming.value).isEqualTo(model.roaming)
+                assertThat(conn.networkName.value)
+                    .isEqualTo(NetworkNameModel.IntentDerived(model.name))
+                assertThat(conn.carrierName.value)
+                    .isEqualTo(NetworkNameModel.SubscriptionDerived("${model.name} ${model.subId}"))
+                assertThat(conn.hasPrioritizedNetworkCapabilities.value).isEqualTo(model.slice)
+                assertThat(conn.isNonTerrestrial.value).isEqualTo(model.ntn)
+
+                // TODO(b/261029387): check these once we start handling them
+                assertThat(conn.isEmergencyOnly.value).isFalse()
+                assertThat(conn.isGsm.value).isFalse()
+                assertThat(conn.dataConnectionState.value).isEqualTo(DataConnectionState.Connected)
+            }
+            // MobileDisabled isn't combinatorial in nature, and is tested in
+            // DemoMobileConnectionsRepositoryTest.kt
+            else -> {}
+        }
+
+        job.cancel()
+    }
+
+    /** Matches [FakeNetworkEventModel] */
+    internal data class TestCase(
+        val level: Int,
+        val dataType: SignalIcon.MobileIconGroup,
+        val subId: Int,
+        val carrierId: Int,
+        val inflateStrength: Boolean,
+        @Annotation.DataActivityType val activity: Int,
+        val carrierNetworkChange: Boolean,
+        val roaming: Boolean,
+        val name: String,
+        val slice: Boolean,
+        val ntn: Boolean,
+    ) {
+        override fun toString(): String {
+            return "INPUT(level=$level, " +
+                "dataType=${dataType.name}, " +
+                "subId=$subId, " +
+                "carrierId=$carrierId, " +
+                "inflateStrength=$inflateStrength, " +
+                "activity=$activity, " +
+                "carrierNetworkChange=$carrierNetworkChange, " +
+                "roaming=$roaming, " +
+                "name=$name," +
+                "slice=$slice" +
+                "ntn=$ntn)"
+        }
+
+        // Convenience for iterating test data and creating new cases
+        fun modifiedBy(
+            level: Int? = null,
+            dataType: SignalIcon.MobileIconGroup? = null,
+            subId: Int? = null,
+            carrierId: Int? = null,
+            inflateStrength: Boolean? = null,
+            @Annotation.DataActivityType activity: Int? = null,
+            carrierNetworkChange: Boolean? = null,
+            roaming: Boolean? = null,
+            name: String? = null,
+            slice: Boolean? = null,
+            ntn: Boolean? = null,
+        ): TestCase =
+            TestCase(
+                level = level ?: this.level,
+                dataType = dataType ?: this.dataType,
+                subId = subId ?: this.subId,
+                carrierId = carrierId ?: this.carrierId,
+                inflateStrength = inflateStrength ?: this.inflateStrength,
+                activity = activity ?: this.activity,
+                carrierNetworkChange = carrierNetworkChange ?: this.carrierNetworkChange,
+                roaming = roaming ?: this.roaming,
+                name = name ?: this.name,
+                slice = slice ?: this.slice,
+                ntn = ntn ?: this.ntn,
+            )
+    }
+
+    companion object {
+        private val subId = 1
+
+        private val booleanList = listOf(true, false)
+        private val levels = listOf(0, 1, 2, 3)
+        private val dataTypes =
+            listOf(
+                TelephonyIcons.THREE_G,
+                TelephonyIcons.LTE,
+                TelephonyIcons.FOUR_G,
+                TelephonyIcons.NR_5G,
+                TelephonyIcons.NR_5G_PLUS,
+            )
+        private val carrierIds = listOf(1, 10, 100)
+        private val inflateStrength = booleanList
+        private val activity =
+            listOf(
+                TelephonyManager.DATA_ACTIVITY_NONE,
+                TelephonyManager.DATA_ACTIVITY_IN,
+                TelephonyManager.DATA_ACTIVITY_OUT,
+                TelephonyManager.DATA_ACTIVITY_INOUT,
+            )
+        private val carrierNetworkChange = booleanList
+        // false first so the base case doesn't have roaming set (more common)
+        private val roaming = listOf(false, true)
+        private val names = listOf("name 1", "name 2")
+        private val slice = listOf(false, true)
+        private val ntn = listOf(false, true)
+
+        @Parameters(name = "{0}") @JvmStatic fun data() = testData()
+
+        /**
+         * Generate some test data. For the sake of convenience, we'll parameterize only non-null
+         * network event data. So given the lists of test data:
+         * ```
+         *    list1 = [1, 2, 3]
+         *    list2 = [false, true]
+         *    list3 = [a, b, c]
+         * ```
+         *
+         * We'll generate test cases for:
+         *
+         * Test (1, false, a) Test (2, false, a) Test (3, false, a) Test (1, true, a) Test (1,
+         * false, b) Test (1, false, c)
+         *
+         * NOTE: this is not a combinatorial product of all of the possible sets of parameters.
+         * Since this test is built to exercise demo mode, the general approach is to define a
+         * fully-formed "base case", and from there to make sure to use every valid parameter once,
+         * by defining the rest of the test cases against the base case. Specific use-cases can be
+         * added to the non-parameterized test, or manually below the generated test cases.
+         */
+        private fun testData(): List<TestCase> {
+            val testSet = mutableSetOf<TestCase>()
+
+            val baseCase =
+                TestCase(
+                    levels.first(),
+                    dataTypes.first(),
+                    subId,
+                    carrierIds.first(),
+                    inflateStrength.first(),
+                    activity.first(),
+                    carrierNetworkChange.first(),
+                    roaming.first(),
+                    names.first(),
+                    slice.first(),
+                    ntn.first(),
+                )
+
+            val tail =
+                sequenceOf(
+                        levels.map { baseCase.modifiedBy(level = it) },
+                        dataTypes.map { baseCase.modifiedBy(dataType = it) },
+                        carrierIds.map { baseCase.modifiedBy(carrierId = it) },
+                        inflateStrength.map { baseCase.modifiedBy(inflateStrength = it) },
+                        activity.map { baseCase.modifiedBy(activity = it) },
+                        carrierNetworkChange.map { baseCase.modifiedBy(carrierNetworkChange = it) },
+                        roaming.map { baseCase.modifiedBy(roaming = it) },
+                        names.map { baseCase.modifiedBy(name = it) },
+                        slice.map { baseCase.modifiedBy(slice = it) },
+                        ntn.map { baseCase.modifiedBy(ntn = it) },
+                    )
+                    .flatten()
+
+            testSet.add(baseCase)
+            tail.toCollection(testSet)
+
+            return testSet.toList()
+        }
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryKairosTest.kt
new file mode 100644
index 0000000..95cdee0
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryKairosTest.kt
@@ -0,0 +1,592 @@
+/*
+ * Copyright (C) 2022 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.demo
+
+import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
+import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.table.tableLogBufferFactory
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
+import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DemoMobileConnectionsRepositoryKairosTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    private val testDispatcher = UnconfinedTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+
+    private val fakeNetworkEventFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
+    private val fakeWifiEventFlow = MutableStateFlow<FakeWifiEventModel?>(null)
+
+    private lateinit var underTest: DemoMobileConnectionsRepositoryKairos
+    private lateinit var mobileDataSource: DemoModeMobileConnectionDataSource
+    private lateinit var wifiDataSource: DemoModeWifiDataSource
+
+    @Before
+    fun setUp() {
+        // The data source only provides one API, so we can mock it with a flow here for convenience
+        mobileDataSource =
+            mock<DemoModeMobileConnectionDataSource>().also {
+                whenever(it.mobileEvents).thenReturn(fakeNetworkEventFlow)
+            }
+        wifiDataSource =
+            mock<DemoModeWifiDataSource>().also {
+                whenever(it.wifiEvents).thenReturn(fakeWifiEventFlow)
+            }
+
+        underTest =
+            DemoMobileConnectionsRepositoryKairos(
+                mobileDataSource = mobileDataSource,
+                wifiDataSource = wifiDataSource,
+                scope = testScope.backgroundScope,
+                context = context,
+                logFactory = kosmos.tableLogBufferFactory,
+            )
+
+        underTest.startProcessingCommands()
+    }
+
+    @Test
+    fun isDefault_defaultsToTrue() =
+        testScope.runTest {
+            val isDefault = underTest.mobileIsDefault.value
+            assertThat(isDefault).isTrue()
+        }
+
+    @Test
+    fun validated_defaultsToTrue() =
+        testScope.runTest {
+            val isValidated = underTest.defaultConnectionIsValidated.value
+            assertThat(isValidated).isTrue()
+        }
+
+    @Test
+    fun networkEvent_createNewSubscription() =
+        testScope.runTest {
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEmpty()
+
+            fakeNetworkEventFlow.value = validMobileEvent(subId = 1)
+
+            assertThat(latest).hasSize(1)
+            assertThat(latest!![0].subscriptionId).isEqualTo(1)
+
+            job.cancel()
+        }
+
+    @Test
+    fun wifiCarrierMergedEvent_createNewSubscription() =
+        testScope.runTest {
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEmpty()
+
+            fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5)
+
+            assertThat(latest).hasSize(1)
+            assertThat(latest!![0].subscriptionId).isEqualTo(5)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkEvent_reusesSubscriptionWhenSameId() =
+        testScope.runTest {
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEmpty()
+
+            fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 1)
+
+            assertThat(latest).hasSize(1)
+            assertThat(latest!![0].subscriptionId).isEqualTo(1)
+
+            // Second network event comes in with the same subId, does not create a new subscription
+            fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 2)
+
+            assertThat(latest).hasSize(1)
+            assertThat(latest!![0].subscriptionId).isEqualTo(1)
+
+            job.cancel()
+        }
+
+    @Test
+    fun wifiCarrierMergedEvent_reusesSubscriptionWhenSameId() =
+        testScope.runTest {
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEmpty()
+
+            fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5, level = 1)
+
+            assertThat(latest).hasSize(1)
+            assertThat(latest!![0].subscriptionId).isEqualTo(5)
+
+            // Second network event comes in with the same subId, does not create a new subscription
+            fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5, level = 2)
+
+            assertThat(latest).hasSize(1)
+            assertThat(latest!![0].subscriptionId).isEqualTo(5)
+
+            job.cancel()
+        }
+
+    @Test
+    fun multipleSubscriptions() =
+        testScope.runTest {
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+            fakeNetworkEventFlow.value = validMobileEvent(subId = 1)
+            fakeNetworkEventFlow.value = validMobileEvent(subId = 2)
+
+            assertThat(latest).hasSize(2)
+
+            job.cancel()
+        }
+
+    @Test
+    fun mobileSubscriptionAndCarrierMergedSubscription() =
+        testScope.runTest {
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+            fakeNetworkEventFlow.value = validMobileEvent(subId = 1)
+            fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5)
+
+            assertThat(latest).hasSize(2)
+
+            job.cancel()
+        }
+
+    @Test
+    fun multipleMobileSubscriptionsAndCarrierMergedSubscription() =
+        testScope.runTest {
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+            fakeNetworkEventFlow.value = validMobileEvent(subId = 1)
+            fakeNetworkEventFlow.value = validMobileEvent(subId = 2)
+            fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 3)
+
+            assertThat(latest).hasSize(3)
+
+            job.cancel()
+        }
+
+    @Test
+    fun mobileDisabledEvent_disablesConnection_subIdSpecified_singleConn() =
+        testScope.runTest {
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+            fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 1)
+
+            fakeNetworkEventFlow.value = MobileDisabled(subId = 1)
+
+            assertThat(latest).hasSize(0)
+
+            job.cancel()
+        }
+
+    @Test
+    fun mobileDisabledEvent_disablesConnection_subIdNotSpecified_singleConn() =
+        testScope.runTest {
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+            fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 1)
+
+            fakeNetworkEventFlow.value = MobileDisabled(subId = null)
+
+            assertThat(latest).hasSize(0)
+
+            job.cancel()
+        }
+
+    @Test
+    fun mobileDisabledEvent_disablesConnection_subIdSpecified_multipleConn() =
+        testScope.runTest {
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+            fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 1)
+            fakeNetworkEventFlow.value = validMobileEvent(subId = 2, level = 1)
+
+            fakeNetworkEventFlow.value = MobileDisabled(subId = 2)
+
+            assertThat(latest).hasSize(1)
+
+            job.cancel()
+        }
+
+    @Test
+    fun mobileDisabledEvent_subIdNotSpecified_multipleConn_ignoresCommand() =
+        testScope.runTest {
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+            fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 1)
+            fakeNetworkEventFlow.value = validMobileEvent(subId = 2, level = 1)
+
+            fakeNetworkEventFlow.value = MobileDisabled(subId = null)
+
+            assertThat(latest).hasSize(2)
+
+            job.cancel()
+        }
+
+    @Test
+    fun wifiNetworkUpdatesToDisabled_carrierMergedConnectionRemoved() =
+        testScope.runTest {
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+            fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 1)
+
+            assertThat(latest).hasSize(1)
+
+            fakeWifiEventFlow.value = FakeWifiEventModel.WifiDisabled
+
+            assertThat(latest).isEmpty()
+
+            job.cancel()
+        }
+
+    @Test
+    fun wifiNetworkUpdatesToActive_carrierMergedConnectionRemoved() =
+        testScope.runTest {
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+            fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 1)
+
+            assertThat(latest).hasSize(1)
+
+            fakeWifiEventFlow.value =
+                FakeWifiEventModel.Wifi(level = 1, activity = 0, ssid = null, validated = true)
+
+            assertThat(latest).isEmpty()
+
+            job.cancel()
+        }
+
+    @Test
+    fun mobileSubUpdatesToCarrierMerged_onlyOneConnection() =
+        testScope.runTest {
+            var latestSubsList: List<SubscriptionModel>? = null
+            var connections: List<DemoMobileConnectionRepository>? = null
+            val job =
+                underTest.subscriptions
+                    .onEach { latestSubsList = it }
+                    .onEach { infos ->
+                        connections =
+                            infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) }
+                    }
+                    .launchIn(this)
+
+            fakeNetworkEventFlow.value = validMobileEvent(subId = 3, level = 2)
+            assertThat(latestSubsList).hasSize(1)
+
+            val carrierMergedEvent = validCarrierMergedEvent(subId = 3, level = 1)
+            fakeWifiEventFlow.value = carrierMergedEvent
+            assertThat(latestSubsList).hasSize(1)
+            val connection = connections!!.find { it.subId == 3 }!!
+            assertCarrierMergedConnection(connection, carrierMergedEvent)
+
+            job.cancel()
+        }
+
+    @Test
+    fun mobileSubUpdatesToCarrierMergedThenBack_hasOldMobileData() =
+        testScope.runTest {
+            var latestSubsList: List<SubscriptionModel>? = null
+            var connections: List<DemoMobileConnectionRepository>? = null
+            val job =
+                underTest.subscriptions
+                    .onEach { latestSubsList = it }
+                    .onEach { infos ->
+                        connections =
+                            infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) }
+                    }
+                    .launchIn(this)
+
+            val mobileEvent = validMobileEvent(subId = 3, level = 2)
+            fakeNetworkEventFlow.value = mobileEvent
+            assertThat(latestSubsList).hasSize(1)
+
+            val carrierMergedEvent = validCarrierMergedEvent(subId = 3, level = 1)
+            fakeWifiEventFlow.value = carrierMergedEvent
+            assertThat(latestSubsList).hasSize(1)
+            var connection = connections!!.find { it.subId == 3 }!!
+            assertCarrierMergedConnection(connection, carrierMergedEvent)
+
+            // WHEN the carrier merged is removed
+            fakeWifiEventFlow.value =
+                FakeWifiEventModel.Wifi(level = 4, activity = 0, ssid = null, validated = true)
+
+            // THEN the subId=3 connection goes back to the mobile information
+            connection = connections!!.find { it.subId == 3 }!!
+            assertConnection(connection, mobileEvent)
+
+            job.cancel()
+        }
+
+    /** Regression test for b/261706421 */
+    @Test
+    fun multipleConnections_removeAll_doesNotThrow() =
+        testScope.runTest {
+            var latest: List<SubscriptionModel>? = null
+            val job = underTest.subscriptions.onEach { latest = it }.launchIn(this)
+
+            // Two subscriptions are added
+            fakeNetworkEventFlow.value = validMobileEvent(subId = 1, level = 1)
+            fakeNetworkEventFlow.value = validMobileEvent(subId = 2, level = 1)
+
+            // Then both are removed by turning off demo mode
+            underTest.stopProcessingCommands()
+
+            assertThat(latest).isEmpty()
+
+            job.cancel()
+        }
+
+    @Test
+    fun demoConnection_singleSubscription() =
+        testScope.runTest {
+            var currentEvent: FakeNetworkEventModel = validMobileEvent(subId = 1)
+            var connections: List<DemoMobileConnectionRepository>? = null
+            val job =
+                underTest.subscriptions
+                    .onEach { infos ->
+                        connections =
+                            infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) }
+                    }
+                    .launchIn(this)
+
+            fakeNetworkEventFlow.value = currentEvent
+
+            assertThat(connections).hasSize(1)
+            val connection1 = connections!![0]
+
+            assertConnection(connection1, currentEvent)
+
+            // Exercise the whole api
+
+            currentEvent = validMobileEvent(subId = 1, level = 2)
+            fakeNetworkEventFlow.value = currentEvent
+            assertConnection(connection1, currentEvent)
+
+            job.cancel()
+        }
+
+    @Test
+    fun demoConnection_twoConnections_updateSecond_noAffectOnFirst() =
+        testScope.runTest {
+            var currentEvent1 = validMobileEvent(subId = 1)
+            var connection1: DemoMobileConnectionRepository? = null
+            var currentEvent2 = validMobileEvent(subId = 2)
+            var connection2: DemoMobileConnectionRepository? = null
+            var connections: List<DemoMobileConnectionRepository>? = null
+            val job =
+                underTest.subscriptions
+                    .onEach { infos ->
+                        connections =
+                            infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) }
+                    }
+                    .launchIn(this)
+
+            fakeNetworkEventFlow.value = currentEvent1
+            fakeNetworkEventFlow.value = currentEvent2
+            assertThat(connections).hasSize(2)
+            connections!!.forEach {
+                if (it.subId == 1) {
+                    connection1 = it
+                } else if (it.subId == 2) {
+                    connection2 = it
+                } else {
+                    Assert.fail("Unexpected subscription")
+                }
+            }
+
+            assertConnection(connection1!!, currentEvent1)
+            assertConnection(connection2!!, currentEvent2)
+
+            // WHEN the event changes for connection 2, it updates, and connection 1 stays the same
+            currentEvent2 = validMobileEvent(subId = 2, activity = DATA_ACTIVITY_INOUT)
+            fakeNetworkEventFlow.value = currentEvent2
+            assertConnection(connection1!!, currentEvent1)
+            assertConnection(connection2!!, currentEvent2)
+
+            // and vice versa
+            currentEvent1 = validMobileEvent(subId = 1, inflateStrength = true)
+            fakeNetworkEventFlow.value = currentEvent1
+            assertConnection(connection1!!, currentEvent1)
+            assertConnection(connection2!!, currentEvent2)
+
+            job.cancel()
+        }
+
+    @Test
+    fun demoConnection_twoConnections_updateCarrierMerged_noAffectOnFirst() =
+        testScope.runTest {
+            var currentEvent1 = validMobileEvent(subId = 1)
+            var connection1: DemoMobileConnectionRepository? = null
+            var currentEvent2 = validCarrierMergedEvent(subId = 2)
+            var connection2: DemoMobileConnectionRepository? = null
+            var connections: List<DemoMobileConnectionRepository>? = null
+            val job =
+                underTest.subscriptions
+                    .onEach { infos ->
+                        connections =
+                            infos.map { info -> underTest.getRepoForSubId(info.subscriptionId) }
+                    }
+                    .launchIn(this)
+
+            fakeNetworkEventFlow.value = currentEvent1
+            fakeWifiEventFlow.value = currentEvent2
+            assertThat(connections).hasSize(2)
+            connections!!.forEach {
+                when (it.subId) {
+                    1 -> connection1 = it
+                    2 -> connection2 = it
+                    else -> Assert.fail("Unexpected subscription")
+                }
+            }
+
+            assertConnection(connection1!!, currentEvent1)
+            assertCarrierMergedConnection(connection2!!, currentEvent2)
+
+            // WHEN the event changes for connection 2, it updates, and connection 1 stays the same
+            currentEvent2 = validCarrierMergedEvent(subId = 2, level = 4)
+            fakeWifiEventFlow.value = currentEvent2
+            assertConnection(connection1!!, currentEvent1)
+            assertCarrierMergedConnection(connection2!!, currentEvent2)
+
+            // and vice versa
+            currentEvent1 = validMobileEvent(subId = 1, inflateStrength = true)
+            fakeNetworkEventFlow.value = currentEvent1
+            assertConnection(connection1!!, currentEvent1)
+            assertCarrierMergedConnection(connection2!!, currentEvent2)
+
+            job.cancel()
+        }
+
+    @Test
+    fun demoIsNotInEcmState() = testScope.runTest { assertThat(underTest.isInEcmMode()).isFalse() }
+
+    private fun TestScope.startCollection(conn: DemoMobileConnectionRepository): Job {
+        val job = launch {
+            launch { conn.cdmaLevel.collect {} }
+            launch { conn.primaryLevel.collect {} }
+            launch { conn.dataActivityDirection.collect {} }
+            launch { conn.carrierNetworkChangeActive.collect {} }
+            launch { conn.isRoaming.collect {} }
+            launch { conn.networkName.collect {} }
+            launch { conn.carrierName.collect {} }
+            launch { conn.isEmergencyOnly.collect {} }
+            launch { conn.dataConnectionState.collect {} }
+            launch { conn.hasPrioritizedNetworkCapabilities.collect {} }
+        }
+        return job
+    }
+
+    private fun TestScope.assertConnection(
+        conn: DemoMobileConnectionRepository,
+        model: FakeNetworkEventModel,
+    ) {
+        val job = startCollection(conn)
+        // Assert the fields using the `MutableStateFlow` so that we don't have to start up
+        // a collector for every field for every test
+        when (model) {
+            is FakeNetworkEventModel.Mobile -> {
+                assertThat(conn.subId).isEqualTo(model.subId)
+                assertThat(conn.cdmaLevel.value).isEqualTo(model.level)
+                assertThat(conn.primaryLevel.value).isEqualTo(model.level)
+                assertThat(conn.dataActivityDirection.value)
+                    .isEqualTo((model.activity ?: DATA_ACTIVITY_NONE).toMobileDataActivityModel())
+                assertThat(conn.carrierNetworkChangeActive.value)
+                    .isEqualTo(model.carrierNetworkChange)
+                assertThat(conn.isRoaming.value).isEqualTo(model.roaming)
+                assertThat(conn.networkName.value)
+                    .isEqualTo(NetworkNameModel.IntentDerived(model.name))
+                assertThat(conn.carrierName.value)
+                    .isEqualTo(NetworkNameModel.SubscriptionDerived("${model.name} ${model.subId}"))
+                assertThat(conn.hasPrioritizedNetworkCapabilities.value).isEqualTo(model.slice)
+                assertThat(conn.isNonTerrestrial.value).isEqualTo(model.ntn)
+
+                // TODO(b/261029387) check these once we start handling them
+                assertThat(conn.isEmergencyOnly.value).isFalse()
+                assertThat(conn.isGsm.value).isFalse()
+                assertThat(conn.dataConnectionState.value).isEqualTo(DataConnectionState.Connected)
+            }
+            else -> {}
+        }
+
+        job.cancel()
+    }
+
+    private fun TestScope.assertCarrierMergedConnection(
+        conn: DemoMobileConnectionRepository,
+        model: FakeWifiEventModel.CarrierMerged,
+    ) {
+        val job = startCollection(conn)
+        assertThat(conn.subId).isEqualTo(model.subscriptionId)
+        assertThat(conn.cdmaLevel.value).isEqualTo(model.level)
+        assertThat(conn.primaryLevel.value).isEqualTo(model.level)
+        assertThat(conn.carrierNetworkChangeActive.value).isEqualTo(false)
+        assertThat(conn.isRoaming.value).isEqualTo(false)
+        assertThat(conn.isEmergencyOnly.value).isFalse()
+        assertThat(conn.isGsm.value).isFalse()
+        assertThat(conn.dataConnectionState.value).isEqualTo(DataConnectionState.Connected)
+        assertThat(conn.hasPrioritizedNetworkCapabilities.value).isFalse()
+        job.cancel()
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryKairosTest.kt
new file mode 100644
index 0000000..93d56d5
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryKairosTest.kt
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2022 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.prod
+
+import android.telephony.TelephonyManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CarrierMergedConnectionRepositoryKairosTest : SysuiTestCase() {
+
+    private lateinit var underTest: CarrierMergedConnectionRepositoryKairos
+
+    private lateinit var wifiRepository: FakeWifiRepository
+    @Mock private lateinit var logger: TableLogBuffer
+    @Mock private lateinit var telephonyManager: TelephonyManager
+
+    private val testDispatcher = UnconfinedTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        whenever(telephonyManager.subscriptionId).thenReturn(SUB_ID)
+        whenever(telephonyManager.simOperatorName).thenReturn("")
+
+        wifiRepository = FakeWifiRepository()
+
+        underTest =
+            CarrierMergedConnectionRepositoryKairos(
+                SUB_ID,
+                logger,
+                telephonyManager,
+                testScope.backgroundScope.coroutineContext,
+                testScope.backgroundScope,
+                wifiRepository,
+            )
+    }
+
+    @Test
+    fun inactiveWifi_isDefault() =
+        testScope.runTest {
+            var latestConnState: DataConnectionState? = null
+            var latestNetType: ResolvedNetworkType? = null
+
+            val dataJob =
+                underTest.dataConnectionState.onEach { latestConnState = it }.launchIn(this)
+            val netJob = underTest.resolvedNetworkType.onEach { latestNetType = it }.launchIn(this)
+
+            wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive())
+
+            assertThat(latestConnState).isEqualTo(DataConnectionState.Disconnected)
+            assertThat(latestNetType).isNotEqualTo(ResolvedNetworkType.CarrierMergedNetworkType)
+
+            dataJob.cancel()
+            netJob.cancel()
+        }
+
+    @Test
+    fun activeWifi_isDefault() =
+        testScope.runTest {
+            var latestConnState: DataConnectionState? = null
+            var latestNetType: ResolvedNetworkType? = null
+
+            val dataJob =
+                underTest.dataConnectionState.onEach { latestConnState = it }.launchIn(this)
+            val netJob = underTest.resolvedNetworkType.onEach { latestNetType = it }.launchIn(this)
+
+            wifiRepository.setWifiNetwork(WifiNetworkModel.Active.of(level = 1))
+
+            assertThat(latestConnState).isEqualTo(DataConnectionState.Disconnected)
+            assertThat(latestNetType).isNotEqualTo(ResolvedNetworkType.CarrierMergedNetworkType)
+
+            dataJob.cancel()
+            netJob.cancel()
+        }
+
+    @Test
+    fun carrierMergedWifi_isValidAndFieldsComeFromWifiNetwork() =
+        testScope.runTest {
+            var latest: Int? = null
+            val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this)
+
+            wifiRepository.setIsWifiEnabled(true)
+            wifiRepository.setIsWifiDefault(true)
+
+            wifiRepository.setWifiNetwork(
+                WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3)
+            )
+
+            assertThat(latest).isEqualTo(3)
+
+            job.cancel()
+        }
+
+    @Test
+    fun activity_comesFromWifiActivity() =
+        testScope.runTest {
+            var latest: DataActivityModel? = null
+            val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this)
+
+            wifiRepository.setIsWifiEnabled(true)
+            wifiRepository.setIsWifiDefault(true)
+            wifiRepository.setWifiNetwork(
+                WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3)
+            )
+            wifiRepository.setWifiActivity(
+                DataActivityModel(hasActivityIn = true, hasActivityOut = false)
+            )
+
+            assertThat(latest!!.hasActivityIn).isTrue()
+            assertThat(latest!!.hasActivityOut).isFalse()
+
+            wifiRepository.setWifiActivity(
+                DataActivityModel(hasActivityIn = false, hasActivityOut = true)
+            )
+
+            assertThat(latest!!.hasActivityIn).isFalse()
+            assertThat(latest!!.hasActivityOut).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun carrierMergedWifi_wrongSubId_isDefault() =
+        testScope.runTest {
+            var latestLevel: Int? = null
+            var latestType: ResolvedNetworkType? = null
+            val levelJob = underTest.primaryLevel.onEach { latestLevel = it }.launchIn(this)
+            val typeJob = underTest.resolvedNetworkType.onEach { latestType = it }.launchIn(this)
+
+            wifiRepository.setWifiNetwork(
+                WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID + 10, level = 3)
+            )
+
+            assertThat(latestLevel).isNotEqualTo(3)
+            assertThat(latestType).isNotEqualTo(ResolvedNetworkType.CarrierMergedNetworkType)
+
+            levelJob.cancel()
+            typeJob.cancel()
+        }
+
+    // This scenario likely isn't possible, but write a test for it anyway
+    @Test
+    fun carrierMergedButNotEnabled_isDefault() =
+        testScope.runTest {
+            var latest: Int? = null
+            val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this)
+
+            wifiRepository.setWifiNetwork(
+                WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3)
+            )
+            wifiRepository.setIsWifiEnabled(false)
+
+            assertThat(latest).isNotEqualTo(3)
+
+            job.cancel()
+        }
+
+    // This scenario likely isn't possible, but write a test for it anyway
+    @Test
+    fun carrierMergedButWifiNotDefault_isDefault() =
+        testScope.runTest {
+            var latest: Int? = null
+            val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this)
+
+            wifiRepository.setWifiNetwork(
+                WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3)
+            )
+            wifiRepository.setIsWifiDefault(false)
+
+            assertThat(latest).isNotEqualTo(3)
+
+            job.cancel()
+        }
+
+    @Test
+    fun numberOfLevels_comesFromCarrierMerged() =
+        testScope.runTest {
+            var latest: Int? = null
+            val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this)
+
+            wifiRepository.setWifiNetwork(
+                WifiNetworkModel.CarrierMerged.of(
+                    subscriptionId = SUB_ID,
+                    level = 1,
+                    numberOfLevels = 6,
+                )
+            )
+
+            assertThat(latest).isEqualTo(6)
+
+            job.cancel()
+        }
+
+    @Test
+    fun dataEnabled_matchesWifiEnabled() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.dataEnabled.onEach { latest = it }.launchIn(this)
+
+            wifiRepository.setIsWifiEnabled(true)
+            assertThat(latest).isTrue()
+
+            wifiRepository.setIsWifiEnabled(false)
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun cdmaRoaming_alwaysFalse() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.cdmaRoaming.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkName_usesSimOperatorNameAsInitial() =
+        testScope.runTest {
+            whenever(telephonyManager.simOperatorName).thenReturn("Test SIM name")
+
+            var latest: NetworkNameModel? = null
+            val job = underTest.networkName.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(NetworkNameModel.SimDerived("Test SIM name"))
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkName_updatesOnNetworkUpdate() =
+        testScope.runTest {
+            whenever(telephonyManager.simOperatorName).thenReturn("Test SIM name")
+
+            var latest: NetworkNameModel? = null
+            val job = underTest.networkName.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(NetworkNameModel.SimDerived("Test SIM name"))
+
+            whenever(telephonyManager.simOperatorName).thenReturn("New SIM name")
+            wifiRepository.setWifiNetwork(
+                WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3)
+            )
+
+            assertThat(latest).isEqualTo(NetworkNameModel.SimDerived("New SIM name"))
+
+            job.cancel()
+        }
+
+    @Test
+    fun isAllowedDuringAirplaneMode_alwaysTrue() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.isAllowedDuringAirplaneMode)
+
+            assertThat(latest).isTrue()
+        }
+
+    private companion object {
+        const val SUB_ID = 123
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryKairosTest.kt
new file mode 100644
index 0000000..56d76fc
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryKairosTest.kt
@@ -0,0 +1,649 @@
+/*
+ * Copyright (C) 2025 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.prod
+
+import android.net.ConnectivityManager
+import android.os.PersistableBundle
+import android.telephony.ServiceState
+import android.telephony.SignalStrength
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
+import android.telephony.TelephonyCallback
+import android.telephony.TelephonyManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags.ROAMING_INDICATOR_VIA_DISPLAY_INFO
+import com.android.systemui.log.table.logcatTableLogBuffer
+import com.android.systemui.log.table.tableLogBufferFactory
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_EMERGENCY
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_OPERATOR
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_PRIMARY_LEVEL
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.getTelephonyCallbackForType
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.StringWriter
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+
+/**
+ * This repo acts as a dispatcher to either the `typical` or `carrier merged` versions of the
+ * repository interface it's switching on. These tests just need to verify that the entire interface
+ * properly switches over when the value of `isCarrierMerged` changes.
+ */
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class FullMobileConnectionRepositoryKairosTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    private lateinit var underTest: FullMobileConnectionRepositoryKairos
+
+    private val flags =
+        FakeFeatureFlagsClassic().also { it.set(ROAMING_INDICATOR_VIA_DISPLAY_INFO, true) }
+
+    private val testDispatcher = UnconfinedTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+    private val tableLogBuffer = logcatTableLogBuffer(kosmos, "TestName")
+    private val mobileFactory = mock<MobileConnectionRepositoryImpl.Factory>()
+    private val carrierMergedFactory = mock<CarrierMergedConnectionRepository.Factory>()
+    private val connectivityManager = mock<ConnectivityManager>()
+
+    private val subscriptionModel =
+        MutableStateFlow(
+            SubscriptionModel(
+                subscriptionId = SUB_ID,
+                carrierName = DEFAULT_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+        )
+
+    // Use a real config, with no overrides
+    private val systemUiCarrierConfig = SystemUiCarrierConfig(SUB_ID, PersistableBundle())
+
+    private lateinit var mobileRepo: FakeMobileConnectionRepository
+    private lateinit var carrierMergedRepo: FakeMobileConnectionRepository
+
+    @Before
+    fun setUp() {
+        mobileRepo = FakeMobileConnectionRepository(SUB_ID, tableLogBuffer)
+        carrierMergedRepo =
+            FakeMobileConnectionRepository(SUB_ID, tableLogBuffer).apply {
+                // Mimicks the real carrier merged repository
+                this.isAllowedDuringAirplaneMode.value = true
+            }
+
+        whenever(mobileFactory.build(eq(SUB_ID), any(), any(), eq(DEFAULT_NAME_MODEL), eq(SEP)))
+            .thenReturn(mobileRepo)
+        whenever(carrierMergedFactory.build(eq(SUB_ID), any())).thenReturn(carrierMergedRepo)
+    }
+
+    @Test
+    fun startingIsCarrierMerged_usesCarrierMergedInitially() =
+        testScope.runTest {
+            val carrierMergedOperatorName = "Carrier Merged Operator"
+            val nonCarrierMergedName = "Non-carrier-merged"
+
+            carrierMergedRepo.operatorAlphaShort.value = carrierMergedOperatorName
+            mobileRepo.operatorAlphaShort.value = nonCarrierMergedName
+
+            initializeRepo(startingIsCarrierMerged = true)
+
+            assertThat(underTest.activeRepo.value).isEqualTo(carrierMergedRepo)
+            assertThat(underTest.operatorAlphaShort.value).isEqualTo(carrierMergedOperatorName)
+            verify(mobileFactory, never())
+                .build(SUB_ID, tableLogBuffer, subscriptionModel, DEFAULT_NAME_MODEL, SEP)
+        }
+
+    @Test
+    fun startingNotCarrierMerged_usesTypicalInitially() =
+        testScope.runTest {
+            val carrierMergedOperatorName = "Carrier Merged Operator"
+            val nonCarrierMergedName = "Typical Operator"
+
+            carrierMergedRepo.operatorAlphaShort.value = carrierMergedOperatorName
+            mobileRepo.operatorAlphaShort.value = nonCarrierMergedName
+
+            initializeRepo(startingIsCarrierMerged = false)
+
+            assertThat(underTest.activeRepo.value).isEqualTo(mobileRepo)
+            assertThat(underTest.operatorAlphaShort.value).isEqualTo(nonCarrierMergedName)
+            verify(carrierMergedFactory, never()).build(SUB_ID, tableLogBuffer)
+        }
+
+    @Test
+    fun activeRepo_matchesIsCarrierMerged() =
+        testScope.runTest {
+            initializeRepo(startingIsCarrierMerged = false)
+            var latest: MobileConnectionRepository? = null
+            val job = underTest.activeRepo.onEach { latest = it }.launchIn(this)
+
+            underTest.setIsCarrierMerged(true)
+
+            assertThat(latest).isEqualTo(carrierMergedRepo)
+
+            underTest.setIsCarrierMerged(false)
+
+            assertThat(latest).isEqualTo(mobileRepo)
+
+            underTest.setIsCarrierMerged(true)
+
+            assertThat(latest).isEqualTo(carrierMergedRepo)
+
+            job.cancel()
+        }
+
+    @Test
+    fun connectionInfo_getsUpdatesFromRepo_carrierMerged() =
+        testScope.runTest {
+            initializeRepo(startingIsCarrierMerged = false)
+
+            var latestName: String? = null
+            var latestLevel: Int? = null
+
+            val nameJob = underTest.operatorAlphaShort.onEach { latestName = it }.launchIn(this)
+            val levelJob = underTest.primaryLevel.onEach { latestLevel = it }.launchIn(this)
+
+            underTest.setIsCarrierMerged(true)
+
+            val operator1 = "Carrier Merged Operator"
+            val level1 = 1
+            carrierMergedRepo.operatorAlphaShort.value = operator1
+            carrierMergedRepo.primaryLevel.value = level1
+
+            assertThat(latestName).isEqualTo(operator1)
+            assertThat(latestLevel).isEqualTo(level1)
+
+            val operator2 = "Carrier Merged Operator #2"
+            val level2 = 2
+            carrierMergedRepo.operatorAlphaShort.value = operator2
+            carrierMergedRepo.primaryLevel.value = level2
+
+            assertThat(latestName).isEqualTo(operator2)
+            assertThat(latestLevel).isEqualTo(level2)
+
+            val operator3 = "Carrier Merged Operator #3"
+            val level3 = 3
+            carrierMergedRepo.operatorAlphaShort.value = operator3
+            carrierMergedRepo.primaryLevel.value = level3
+
+            assertThat(latestName).isEqualTo(operator3)
+            assertThat(latestLevel).isEqualTo(level3)
+
+            nameJob.cancel()
+            levelJob.cancel()
+        }
+
+    @Test
+    fun connectionInfo_getsUpdatesFromRepo_mobile() =
+        testScope.runTest {
+            initializeRepo(startingIsCarrierMerged = false)
+
+            var latestName: String? = null
+            var latestLevel: Int? = null
+
+            val nameJob = underTest.operatorAlphaShort.onEach { latestName = it }.launchIn(this)
+            val levelJob = underTest.primaryLevel.onEach { latestLevel = it }.launchIn(this)
+
+            underTest.setIsCarrierMerged(false)
+
+            val operator1 = "Typical Merged Operator"
+            val level1 = 1
+            mobileRepo.operatorAlphaShort.value = operator1
+            mobileRepo.primaryLevel.value = level1
+
+            assertThat(latestName).isEqualTo(operator1)
+            assertThat(latestLevel).isEqualTo(level1)
+
+            val operator2 = "Typical Merged Operator #2"
+            val level2 = 2
+            mobileRepo.operatorAlphaShort.value = operator2
+            mobileRepo.primaryLevel.value = level2
+
+            assertThat(latestName).isEqualTo(operator2)
+            assertThat(latestLevel).isEqualTo(level2)
+
+            val operator3 = "Typical Merged Operator #3"
+            val level3 = 3
+            mobileRepo.operatorAlphaShort.value = operator3
+            mobileRepo.primaryLevel.value = level3
+
+            assertThat(latestName).isEqualTo(operator3)
+            assertThat(latestLevel).isEqualTo(level3)
+
+            nameJob.cancel()
+            levelJob.cancel()
+        }
+
+    @Test
+    fun connectionInfo_updatesWhenCarrierMergedUpdates() =
+        testScope.runTest {
+            initializeRepo(startingIsCarrierMerged = false)
+
+            var latestName: String? = null
+            var latestLevel: Int? = null
+
+            val nameJob = underTest.operatorAlphaShort.onEach { latestName = it }.launchIn(this)
+            val levelJob = underTest.primaryLevel.onEach { latestLevel = it }.launchIn(this)
+
+            val carrierMergedOperator = "Carrier Merged Operator"
+            val carrierMergedLevel = 4
+            carrierMergedRepo.operatorAlphaShort.value = carrierMergedOperator
+            carrierMergedRepo.primaryLevel.value = carrierMergedLevel
+
+            val mobileName = "Typical Operator"
+            val mobileLevel = 2
+            mobileRepo.operatorAlphaShort.value = mobileName
+            mobileRepo.primaryLevel.value = mobileLevel
+
+            // Start with the mobile info
+            assertThat(latestName).isEqualTo(mobileName)
+            assertThat(latestLevel).isEqualTo(mobileLevel)
+
+            // WHEN isCarrierMerged is set to true
+            underTest.setIsCarrierMerged(true)
+
+            // THEN the carrier merged info is used
+            assertThat(latestName).isEqualTo(carrierMergedOperator)
+            assertThat(latestLevel).isEqualTo(carrierMergedLevel)
+
+            val newCarrierMergedName = "New CM Operator"
+            val newCarrierMergedLevel = 0
+            carrierMergedRepo.operatorAlphaShort.value = newCarrierMergedName
+            carrierMergedRepo.primaryLevel.value = newCarrierMergedLevel
+
+            assertThat(latestName).isEqualTo(newCarrierMergedName)
+            assertThat(latestLevel).isEqualTo(newCarrierMergedLevel)
+
+            // WHEN isCarrierMerged is set to false
+            underTest.setIsCarrierMerged(false)
+
+            // THEN the typical info is used
+            assertThat(latestName).isEqualTo(mobileName)
+            assertThat(latestLevel).isEqualTo(mobileLevel)
+
+            val newMobileName = "New MobileOperator"
+            val newMobileLevel = 3
+            mobileRepo.operatorAlphaShort.value = newMobileName
+            mobileRepo.primaryLevel.value = newMobileLevel
+
+            assertThat(latestName).isEqualTo(newMobileName)
+            assertThat(latestLevel).isEqualTo(newMobileLevel)
+
+            nameJob.cancel()
+            levelJob.cancel()
+        }
+
+    @Test
+    fun isAllowedDuringAirplaneMode_updatesWhenCarrierMergedUpdates() =
+        testScope.runTest {
+            initializeRepo(startingIsCarrierMerged = false)
+
+            val latest by collectLastValue(underTest.isAllowedDuringAirplaneMode)
+
+            assertThat(latest).isFalse()
+
+            underTest.setIsCarrierMerged(true)
+
+            assertThat(latest).isTrue()
+
+            underTest.setIsCarrierMerged(false)
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun factory_reusesLogBuffersForSameConnection() =
+        testScope.runTest {
+            val factory =
+                FullMobileConnectionRepository.Factory(
+                    scope = testScope.backgroundScope,
+                    kosmos.tableLogBufferFactory,
+                    mobileFactory,
+                    carrierMergedFactory,
+                )
+
+            // Create two connections for the same subId. Similar to if the connection appeared
+            // and disappeared from the connectionFactory's perspective
+            val connection1 =
+                factory.build(
+                    SUB_ID,
+                    startingIsCarrierMerged = false,
+                    subscriptionModel,
+                    DEFAULT_NAME_MODEL,
+                    SEP,
+                )
+
+            val connection1Repeat =
+                factory.build(
+                    SUB_ID,
+                    startingIsCarrierMerged = false,
+                    subscriptionModel,
+                    DEFAULT_NAME_MODEL,
+                    SEP,
+                )
+
+            assertThat(connection1.tableLogBuffer)
+                .isSameInstanceAs(connection1Repeat.tableLogBuffer)
+        }
+
+    @Test
+    fun factory_reusesLogBuffersForSameSubIDevenIfCarrierMerged() =
+        testScope.runTest {
+            val factory =
+                FullMobileConnectionRepository.Factory(
+                    scope = testScope.backgroundScope,
+                    kosmos.tableLogBufferFactory,
+                    mobileFactory,
+                    carrierMergedFactory,
+                )
+
+            val connection1 =
+                factory.build(
+                    SUB_ID,
+                    startingIsCarrierMerged = false,
+                    subscriptionModel,
+                    DEFAULT_NAME_MODEL,
+                    SEP,
+                )
+
+            // WHEN a connection with the same sub ID but carrierMerged = true is created
+            val connection1Repeat =
+                factory.build(
+                    SUB_ID,
+                    startingIsCarrierMerged = true,
+                    subscriptionModel,
+                    DEFAULT_NAME_MODEL,
+                    SEP,
+                )
+
+            // THEN the same table is re-used
+            assertThat(connection1.tableLogBuffer)
+                .isSameInstanceAs(connection1Repeat.tableLogBuffer)
+        }
+
+    @Test
+    fun connectionInfo_logging_notCarrierMerged_getsUpdates() =
+        testScope.runTest {
+            // SETUP: Use real repositories to verify the diffing still works. (See b/267501739.)
+            val telephonyManager =
+                mock<TelephonyManager>().apply { whenever(this.simOperatorName).thenReturn("") }
+            createRealMobileRepo(telephonyManager)
+            createRealCarrierMergedRepo(telephonyManager, FakeWifiRepository())
+
+            initializeRepo(startingIsCarrierMerged = false)
+
+            val emergencyJob = underTest.isEmergencyOnly.launchIn(this)
+            val operatorJob = underTest.operatorAlphaShort.launchIn(this)
+
+            // WHEN we set up some mobile connection info
+            val serviceState = ServiceState()
+            serviceState.setOperatorName("longName", "OpTypical", "1")
+            serviceState.isEmergencyOnly = true
+            getTelephonyCallbackForType<TelephonyCallback.ServiceStateListener>(telephonyManager)
+                .onServiceStateChanged(serviceState)
+
+            // THEN it's logged to the buffer
+            assertThat(dumpBuffer()).contains("$COL_OPERATOR${BUFFER_SEPARATOR}OpTypical")
+            assertThat(dumpBuffer()).contains("$COL_EMERGENCY${BUFFER_SEPARATOR}true")
+
+            // WHEN we update mobile connection info
+            val serviceState2 = ServiceState()
+            serviceState2.setOperatorName("longName", "OpDiff", "1")
+            serviceState2.isEmergencyOnly = false
+            getTelephonyCallbackForType<TelephonyCallback.ServiceStateListener>(telephonyManager)
+                .onServiceStateChanged(serviceState2)
+
+            // THEN the updates are logged
+            assertThat(dumpBuffer()).contains("$COL_OPERATOR${BUFFER_SEPARATOR}OpDiff")
+            assertThat(dumpBuffer()).contains("$COL_EMERGENCY${BUFFER_SEPARATOR}false")
+
+            emergencyJob.cancel()
+            operatorJob.cancel()
+        }
+
+    @Test
+    fun connectionInfo_logging_carrierMerged_getsUpdates() =
+        testScope.runTest {
+            // SETUP: Use real repositories to verify the diffing still works. (See b/267501739.)
+            val telephonyManager =
+                mock<TelephonyManager>().apply { whenever(this.simOperatorName).thenReturn("") }
+            createRealMobileRepo(telephonyManager)
+            val wifiRepository = FakeWifiRepository()
+            createRealCarrierMergedRepo(telephonyManager, wifiRepository)
+
+            initializeRepo(startingIsCarrierMerged = true)
+
+            val job = underTest.primaryLevel.launchIn(this)
+
+            // WHEN we set up carrier merged info
+            wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged.of(SUB_ID, level = 3))
+
+            // THEN the carrier merged info is logged
+            assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}3")
+
+            // WHEN we update the info
+            wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged.of(SUB_ID, level = 1))
+
+            // THEN the updates are logged
+            assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}1")
+
+            job.cancel()
+        }
+
+    @Test
+    fun connectionInfo_logging_updatesWhenCarrierMergedUpdates() =
+        testScope.runTest {
+            // SETUP: Use real repositories to verify the diffing still works. (See b/267501739.)
+            val telephonyManager =
+                mock<TelephonyManager>().apply { whenever(this.simOperatorName).thenReturn("") }
+            createRealMobileRepo(telephonyManager)
+
+            val wifiRepository = FakeWifiRepository()
+            createRealCarrierMergedRepo(telephonyManager, wifiRepository)
+
+            initializeRepo(startingIsCarrierMerged = false)
+
+            val job = underTest.primaryLevel.launchIn(this)
+
+            // WHEN we set up some mobile connection info
+            val signalStrength = mock<SignalStrength>()
+            whenever(signalStrength.level).thenReturn(1)
+
+            getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>(telephonyManager)
+                .onSignalStrengthsChanged(signalStrength)
+
+            // THEN it's logged to the buffer
+            assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}1")
+
+            // WHEN isCarrierMerged is set to true
+            wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged.of(SUB_ID, level = 3))
+            underTest.setIsCarrierMerged(true)
+
+            // THEN the carrier merged info is logged
+            assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}3")
+
+            // WHEN the carrier merge network is updated
+            wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged.of(SUB_ID, level = 4))
+
+            // THEN the new level is logged
+            assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}4")
+
+            // WHEN isCarrierMerged is set to false
+            underTest.setIsCarrierMerged(false)
+
+            // THEN the typical info is logged
+            // Note: Since our first logs also had the typical info, we need to search the log
+            // contents for after our carrier merged level log.
+            val fullBuffer = dumpBuffer()
+            val carrierMergedContentIndex = fullBuffer.indexOf("${BUFFER_SEPARATOR}4")
+            val bufferAfterCarrierMerged = fullBuffer.substring(carrierMergedContentIndex)
+            assertThat(bufferAfterCarrierMerged).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}1")
+
+            // WHEN the normal network is updated
+            mobileRepo.primaryLevel.value = 0
+
+            // THEN the new level is logged
+            assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}0")
+
+            job.cancel()
+        }
+
+    @Test
+    fun connectionInfo_logging_doesNotLogUpdatesForNotActiveRepo() =
+        testScope.runTest {
+            // SETUP: Use real repositories to verify the diffing still works. (See b/267501739.)
+            val telephonyManager =
+                mock<TelephonyManager>().apply { whenever(this.simOperatorName).thenReturn("") }
+            createRealMobileRepo(telephonyManager)
+
+            val wifiRepository = FakeWifiRepository()
+            createRealCarrierMergedRepo(telephonyManager, wifiRepository)
+
+            // WHEN isCarrierMerged = false
+            initializeRepo(startingIsCarrierMerged = false)
+
+            val job = underTest.primaryLevel.launchIn(this)
+
+            val signalStrength = mock<SignalStrength>()
+            whenever(signalStrength.level).thenReturn(1)
+            getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>(telephonyManager)
+                .onSignalStrengthsChanged(signalStrength)
+
+            // THEN updates to the carrier merged level aren't logged
+            wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged.of(SUB_ID, level = 4))
+            assertThat(dumpBuffer()).doesNotContain("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}4")
+
+            wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged.of(SUB_ID, level = 3))
+            assertThat(dumpBuffer()).doesNotContain("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}3")
+
+            // WHEN isCarrierMerged is set to true
+            underTest.setIsCarrierMerged(true)
+
+            // THEN updates to the normal level aren't logged
+            whenever(signalStrength.level).thenReturn(5)
+            getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>(telephonyManager)
+                .onSignalStrengthsChanged(signalStrength)
+            assertThat(dumpBuffer()).doesNotContain("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}5")
+
+            whenever(signalStrength.level).thenReturn(6)
+            getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>(telephonyManager)
+                .onSignalStrengthsChanged(signalStrength)
+            assertThat(dumpBuffer()).doesNotContain("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}6")
+
+            job.cancel()
+        }
+
+    private fun initializeRepo(startingIsCarrierMerged: Boolean) {
+        underTest =
+            FullMobileConnectionRepositoryKairos(
+                SUB_ID,
+                startingIsCarrierMerged,
+                tableLogBuffer,
+                subscriptionModel,
+                DEFAULT_NAME_MODEL,
+                SEP,
+                testScope.backgroundScope,
+                mobileFactory,
+                carrierMergedFactory,
+            )
+    }
+
+    private fun createRealMobileRepo(
+        telephonyManager: TelephonyManager
+    ): MobileConnectionRepositoryImpl {
+        whenever(telephonyManager.subscriptionId).thenReturn(SUB_ID)
+        val realRepo =
+            MobileConnectionRepositoryImpl(
+                SUB_ID,
+                context,
+                subscriptionModel,
+                DEFAULT_NAME_MODEL,
+                SEP,
+                connectivityManager,
+                telephonyManager,
+                systemUiCarrierConfig = systemUiCarrierConfig,
+                fakeBroadcastDispatcher,
+                mobileMappingsProxy = mock(),
+                testDispatcher,
+                logger = mock(),
+                tableLogBuffer,
+                flags,
+                testScope.backgroundScope,
+            )
+        whenever(mobileFactory.build(eq(SUB_ID), any(), any(), eq(DEFAULT_NAME_MODEL), eq(SEP)))
+            .thenReturn(realRepo)
+
+        return realRepo
+    }
+
+    private fun createRealCarrierMergedRepo(
+        telephonyManager: TelephonyManager,
+        wifiRepository: FakeWifiRepository,
+    ): CarrierMergedConnectionRepository {
+        wifiRepository.setIsWifiEnabled(true)
+        wifiRepository.setIsWifiDefault(true)
+        val realRepo =
+            CarrierMergedConnectionRepository(
+                SUB_ID,
+                tableLogBuffer,
+                telephonyManager,
+                testScope.backgroundScope.coroutineContext,
+                testScope.backgroundScope,
+                wifiRepository,
+            )
+        whenever(carrierMergedFactory.build(eq(SUB_ID), any())).thenReturn(realRepo)
+
+        return realRepo
+    }
+
+    private fun dumpBuffer(): String {
+        val outputWriter = StringWriter()
+        tableLogBuffer.dump(PrintWriter(outputWriter), arrayOf())
+        return outputWriter.toString()
+    }
+
+    private companion object {
+        const val SUB_ID = 42
+        private const val DEFAULT_NAME = "default name"
+        private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
+        private const val SEP = "-"
+        private const val BUFFER_SEPARATOR = "|"
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosTest.kt
new file mode 100644
index 0000000..3a335b7
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosTest.kt
@@ -0,0 +1,1454 @@
+/*
+ * Copyright (C) 2025 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.prod
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.net.ConnectivityManager
+import android.net.ConnectivityManager.NetworkCallback
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WLAN
+import android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN
+import android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL
+import android.telephony.CarrierConfigManager.KEY_SHOW_5G_SLICE_ICON_BOOL
+import android.telephony.NetworkRegistrationInfo
+import android.telephony.NetworkRegistrationInfo.DOMAIN_PS
+import android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_DENIED
+import android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME
+import android.telephony.ServiceState
+import android.telephony.ServiceState.STATE_IN_SERVICE
+import android.telephony.ServiceState.STATE_OUT_OF_SERVICE
+import android.telephony.SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
+import android.telephony.TelephonyCallback
+import android.telephony.TelephonyCallback.CarrierRoamingNtnListener
+import android.telephony.TelephonyCallback.DataActivityListener
+import android.telephony.TelephonyCallback.DisplayInfoListener
+import android.telephony.TelephonyCallback.ServiceStateListener
+import android.telephony.TelephonyDisplayInfo
+import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA
+import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
+import android.telephony.TelephonyManager
+import android.telephony.TelephonyManager.DATA_ACTIVITY_DORMANT
+import android.telephony.TelephonyManager.DATA_ACTIVITY_IN
+import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
+import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
+import android.telephony.TelephonyManager.DATA_ACTIVITY_OUT
+import android.telephony.TelephonyManager.DATA_CONNECTED
+import android.telephony.TelephonyManager.DATA_CONNECTING
+import android.telephony.TelephonyManager.DATA_DISCONNECTED
+import android.telephony.TelephonyManager.DATA_DISCONNECTING
+import android.telephony.TelephonyManager.DATA_HANDOVER_IN_PROGRESS
+import android.telephony.TelephonyManager.DATA_SUSPENDED
+import android.telephony.TelephonyManager.DATA_UNKNOWN
+import android.telephony.TelephonyManager.ERI_OFF
+import android.telephony.TelephonyManager.ERI_ON
+import android.telephony.TelephonyManager.EXTRA_CARRIER_ID
+import android.telephony.TelephonyManager.EXTRA_DATA_SPN
+import android.telephony.TelephonyManager.EXTRA_PLMN
+import android.telephony.TelephonyManager.EXTRA_SHOW_PLMN
+import android.telephony.TelephonyManager.EXTRA_SHOW_SPN
+import android.telephony.TelephonyManager.EXTRA_SPN
+import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID
+import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
+import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.mobile.MobileMappings
+import com.android.systemui.Flags
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags.ROAMING_INDICATOR_VIA_DISPLAY_INFO
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfigWithOverride
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.signalStrength
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.telephonyDisplayInfo
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MobileConnectionRepositoryKairosTest : SysuiTestCase() {
+    private lateinit var underTest: MobileConnectionRepositoryKairosImpl
+
+    private val flags =
+        FakeFeatureFlagsClassic().also { it.set(ROAMING_INDICATOR_VIA_DISPLAY_INFO, true) }
+
+    @Mock private lateinit var connectivityManager: ConnectivityManager
+    @Mock private lateinit var telephonyManager: TelephonyManager
+    @Mock private lateinit var logger: MobileInputLogger
+    @Mock private lateinit var tableLogger: TableLogBuffer
+    @Mock private lateinit var context: Context
+
+    private val mobileMappings = FakeMobileMappingsProxy()
+    private val systemUiCarrierConfig = SystemUiCarrierConfig(SUB_1_ID, testCarrierConfig())
+
+    private val testDispatcher = UnconfinedTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+
+    private val subscriptionModel: MutableStateFlow<SubscriptionModel?> =
+        MutableStateFlow(
+            SubscriptionModel(
+                subscriptionId = SUB_1_ID,
+                carrierName = DEFAULT_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+        )
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        whenever(telephonyManager.subscriptionId).thenReturn(SUB_1_ID)
+
+        underTest =
+            MobileConnectionRepositoryKairosImpl(
+                SUB_1_ID,
+                context,
+                subscriptionModel,
+                DEFAULT_NAME_MODEL,
+                SEP,
+                connectivityManager,
+                telephonyManager,
+                systemUiCarrierConfig,
+                fakeBroadcastDispatcher,
+                mobileMappings,
+                testDispatcher,
+                logger,
+                tableLogger,
+                flags,
+                testScope.backgroundScope,
+            )
+    }
+
+    @Test
+    fun emergencyOnly() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isEmergencyOnly.onEach { latest = it }.launchIn(this)
+
+            val serviceState = ServiceState()
+            serviceState.isEmergencyOnly = true
+
+            getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
+
+            assertThat(latest).isEqualTo(true)
+
+            job.cancel()
+        }
+
+    @Test
+    fun emergencyOnly_toggles() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isEmergencyOnly.onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<ServiceStateListener>()
+            callback.onServiceStateChanged(ServiceState().also { it.isEmergencyOnly = true })
+            assertThat(latest).isTrue()
+
+            callback.onServiceStateChanged(ServiceState().also { it.isEmergencyOnly = false })
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun cdmaLevelUpdates() =
+        testScope.runTest {
+            var latest: Int? = null
+            val job = underTest.cdmaLevel.onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>()
+            var strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true)
+            callback.onSignalStrengthsChanged(strength)
+
+            assertThat(latest).isEqualTo(2)
+
+            // gsmLevel updates, no change to cdmaLevel
+            strength = signalStrength(gsmLevel = 3, cdmaLevel = 2, isGsm = true)
+            callback.onSignalStrengthsChanged(strength)
+
+            assertThat(latest).isEqualTo(2)
+
+            job.cancel()
+        }
+
+    @Test
+    fun gsmLevelUpdates() =
+        testScope.runTest {
+            var latest: Int? = null
+            val job = underTest.primaryLevel.onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>()
+            var strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true)
+            callback.onSignalStrengthsChanged(strength)
+
+            assertThat(latest).isEqualTo(1)
+
+            strength = signalStrength(gsmLevel = 3, cdmaLevel = 2, isGsm = true)
+            callback.onSignalStrengthsChanged(strength)
+
+            assertThat(latest).isEqualTo(3)
+
+            job.cancel()
+        }
+
+    @Test
+    fun isGsm() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isGsm.onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>()
+            var strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true)
+            callback.onSignalStrengthsChanged(strength)
+
+            assertThat(latest).isTrue()
+
+            strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = false)
+            callback.onSignalStrengthsChanged(strength)
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun dataConnectionState_connected() =
+        testScope.runTest {
+            var latest: DataConnectionState? = null
+            val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
+
+            val callback =
+                getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
+            callback.onDataConnectionStateChanged(DATA_CONNECTED, 200 /* unused */)
+
+            assertThat(latest).isEqualTo(DataConnectionState.Connected)
+
+            job.cancel()
+        }
+
+    @Test
+    fun dataConnectionState_connecting() =
+        testScope.runTest {
+            var latest: DataConnectionState? = null
+            val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
+
+            val callback =
+                getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
+            callback.onDataConnectionStateChanged(DATA_CONNECTING, 200 /* unused */)
+
+            assertThat(latest).isEqualTo(DataConnectionState.Connecting)
+
+            job.cancel()
+        }
+
+    @Test
+    fun dataConnectionState_disconnected() =
+        testScope.runTest {
+            var latest: DataConnectionState? = null
+            val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
+
+            val callback =
+                getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
+            callback.onDataConnectionStateChanged(DATA_DISCONNECTED, 200 /* unused */)
+
+            assertThat(latest).isEqualTo(DataConnectionState.Disconnected)
+
+            job.cancel()
+        }
+
+    @Test
+    fun dataConnectionState_disconnecting() =
+        testScope.runTest {
+            var latest: DataConnectionState? = null
+            val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
+
+            val callback =
+                getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
+            callback.onDataConnectionStateChanged(DATA_DISCONNECTING, 200 /* unused */)
+
+            assertThat(latest).isEqualTo(DataConnectionState.Disconnecting)
+
+            job.cancel()
+        }
+
+    @Test
+    fun dataConnectionState_suspended() =
+        testScope.runTest {
+            var latest: DataConnectionState? = null
+            val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
+
+            val callback =
+                getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
+            callback.onDataConnectionStateChanged(DATA_SUSPENDED, 200 /* unused */)
+
+            assertThat(latest).isEqualTo(DataConnectionState.Suspended)
+
+            job.cancel()
+        }
+
+    @Test
+    fun dataConnectionState_handoverInProgress() =
+        testScope.runTest {
+            var latest: DataConnectionState? = null
+            val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
+
+            val callback =
+                getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
+            callback.onDataConnectionStateChanged(DATA_HANDOVER_IN_PROGRESS, 200 /* unused */)
+
+            assertThat(latest).isEqualTo(DataConnectionState.HandoverInProgress)
+
+            job.cancel()
+        }
+
+    @Test
+    fun dataConnectionState_unknown() =
+        testScope.runTest {
+            var latest: DataConnectionState? = null
+            val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
+
+            val callback =
+                getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
+            callback.onDataConnectionStateChanged(DATA_UNKNOWN, 200 /* unused */)
+
+            assertThat(latest).isEqualTo(DataConnectionState.Unknown)
+
+            job.cancel()
+        }
+
+    @Test
+    fun dataConnectionState_invalid() =
+        testScope.runTest {
+            var latest: DataConnectionState? = null
+            val job = underTest.dataConnectionState.onEach { latest = it }.launchIn(this)
+
+            val callback =
+                getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
+            callback.onDataConnectionStateChanged(45, 200 /* unused */)
+
+            assertThat(latest).isEqualTo(DataConnectionState.Invalid)
+
+            job.cancel()
+        }
+
+    @Test
+    fun dataActivity() =
+        testScope.runTest {
+            var latest: DataActivityModel? = null
+            val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<DataActivityListener>()
+            callback.onDataActivity(DATA_ACTIVITY_INOUT)
+
+            assertThat(latest).isEqualTo(DATA_ACTIVITY_INOUT.toMobileDataActivityModel())
+
+            job.cancel()
+        }
+
+    @Test
+    fun carrierId_initialValueCaptured() =
+        testScope.runTest {
+            whenever(telephonyManager.simCarrierId).thenReturn(1234)
+
+            var latest: Int? = null
+            val job = underTest.carrierId.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(1234)
+
+            job.cancel()
+        }
+
+    @Test
+    fun carrierId_updatesOnBroadcast() =
+        testScope.runTest {
+            whenever(telephonyManager.simCarrierId).thenReturn(1234)
+
+            var latest: Int? = null
+            val job = underTest.carrierId.onEach { latest = it }.launchIn(this)
+
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+                context,
+                carrierIdIntent(carrierId = 4321),
+            )
+
+            assertThat(latest).isEqualTo(4321)
+
+            job.cancel()
+        }
+
+    @Test
+    fun carrierNetworkChange() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.carrierNetworkChangeActive.onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<TelephonyCallback.CarrierNetworkListener>()
+            callback.onCarrierNetworkChange(true)
+
+            assertThat(latest).isEqualTo(true)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkType_default() =
+        testScope.runTest {
+            var latest: ResolvedNetworkType? = null
+            val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
+
+            val expected = UnknownNetworkType
+
+            assertThat(latest).isEqualTo(expected)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkType_unknown_hasCorrectKey() =
+        testScope.runTest {
+            var latest: ResolvedNetworkType? = null
+            val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
+            val ti =
+                telephonyDisplayInfo(
+                    networkType = NETWORK_TYPE_UNKNOWN,
+                    overrideNetworkType = NETWORK_TYPE_UNKNOWN,
+                )
+
+            callback.onDisplayInfoChanged(ti)
+
+            val expected = UnknownNetworkType
+            assertThat(latest).isEqualTo(expected)
+            assertThat(latest!!.lookupKey).isEqualTo(MobileMappings.toIconKey(NETWORK_TYPE_UNKNOWN))
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkType_updatesUsingDefault() =
+        testScope.runTest {
+            var latest: ResolvedNetworkType? = null
+            val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
+            val overrideType = OVERRIDE_NETWORK_TYPE_NONE
+            val type = NETWORK_TYPE_LTE
+            val ti = telephonyDisplayInfo(networkType = type, overrideNetworkType = overrideType)
+            callback.onDisplayInfoChanged(ti)
+
+            val expected = DefaultNetworkType(mobileMappings.toIconKey(type))
+            assertThat(latest).isEqualTo(expected)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkType_updatesUsingOverride() =
+        testScope.runTest {
+            var latest: ResolvedNetworkType? = null
+            val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
+            val type = OVERRIDE_NETWORK_TYPE_LTE_CA
+            val ti = telephonyDisplayInfo(networkType = type, overrideNetworkType = type)
+            callback.onDisplayInfoChanged(ti)
+
+            val expected = OverrideNetworkType(mobileMappings.toIconKeyOverride(type))
+            assertThat(latest).isEqualTo(expected)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkType_unknownNetworkWithOverride_usesOverrideKey() =
+        testScope.runTest {
+            var latest: ResolvedNetworkType? = null
+            val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
+            val unknown = NETWORK_TYPE_UNKNOWN
+            val type = OVERRIDE_NETWORK_TYPE_LTE_CA
+            val ti = telephonyDisplayInfo(unknown, type)
+            callback.onDisplayInfoChanged(ti)
+
+            val expected = OverrideNetworkType(mobileMappings.toIconKeyOverride(type))
+            assertThat(latest).isEqualTo(expected)
+
+            job.cancel()
+        }
+
+    @Test
+    fun dataEnabled_initial_false() =
+        testScope.runTest {
+            whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false)
+
+            assertThat(underTest.dataEnabled.value).isFalse()
+        }
+
+    @Test
+    fun isDataEnabled_tracksTelephonyCallback() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.dataEnabled.onEach { latest = it }.launchIn(this)
+
+            whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false)
+            assertThat(underTest.dataEnabled.value).isFalse()
+
+            val callback = getTelephonyCallbackForType<TelephonyCallback.DataEnabledListener>()
+
+            callback.onDataEnabledChanged(true, 1)
+            assertThat(latest).isTrue()
+
+            callback.onDataEnabledChanged(false, 1)
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun numberOfLevels_isDefault() =
+        testScope.runTest {
+            var latest: Int? = null
+            val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS)
+
+            job.cancel()
+        }
+
+    @Test
+    fun roaming_cdma_queriesTelephonyManager() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.cdmaRoaming.onEach { latest = it }.launchIn(this)
+
+            val cb = getTelephonyCallbackForType<ServiceStateListener>()
+
+            // CDMA roaming is off, GSM roaming is on
+            whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_OFF)
+            cb.onServiceStateChanged(ServiceState().also { it.roaming = true })
+
+            assertThat(latest).isFalse()
+
+            // CDMA roaming is on, GSM roaming is off
+            whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_ON)
+            cb.onServiceStateChanged(ServiceState().also { it.roaming = false })
+
+            assertThat(latest).isTrue()
+
+            job.cancel()
+        }
+
+    /**
+     * [TelephonyManager.getCdmaEnhancedRoamingIndicatorDisplayNumber] returns -1 if the service is
+     * not running or if there is an error while retrieving the cdma ERI
+     */
+    @Test
+    fun cdmaRoaming_ignoresNegativeOne() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.cdmaRoaming.onEach { latest = it }.launchIn(this)
+
+            val serviceState = ServiceState()
+            serviceState.roaming = false
+
+            val cb = getTelephonyCallbackForType<ServiceStateListener>()
+
+            // CDMA roaming is unavailable (-1), GSM roaming is off
+            whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(-1)
+            cb.onServiceStateChanged(serviceState)
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun roaming_gsm_queriesDisplayInfo_viaDisplayInfo() =
+        testScope.runTest {
+            // GIVEN flag is true
+            flags.set(ROAMING_INDICATOR_VIA_DISPLAY_INFO, true)
+
+            // Re-create the repository, because the flag is read at init
+            underTest =
+                MobileConnectionRepositoryKairosImpl(
+                    SUB_1_ID,
+                    context,
+                    subscriptionModel,
+                    DEFAULT_NAME_MODEL,
+                    SEP,
+                    connectivityManager,
+                    telephonyManager,
+                    systemUiCarrierConfig,
+                    fakeBroadcastDispatcher,
+                    mobileMappings,
+                    testDispatcher,
+                    logger,
+                    tableLogger,
+                    flags,
+                    testScope.backgroundScope,
+                )
+
+            var latest: Boolean? = null
+            val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
+
+            val cb = getTelephonyCallbackForType<DisplayInfoListener>()
+
+            // CDMA roaming is off, GSM roaming is off
+            whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_OFF)
+            cb.onDisplayInfoChanged(
+                TelephonyDisplayInfo(NETWORK_TYPE_LTE, NETWORK_TYPE_UNKNOWN, false, false, false)
+            )
+
+            assertThat(latest).isFalse()
+
+            // CDMA roaming is off, GSM roaming is on
+            cb.onDisplayInfoChanged(
+                TelephonyDisplayInfo(NETWORK_TYPE_LTE, NETWORK_TYPE_UNKNOWN, true, false, false)
+            )
+
+            assertThat(latest).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun roaming_gsm_queriesDisplayInfo_viaServiceState() =
+        testScope.runTest {
+            // GIVEN flag is false
+            flags.set(ROAMING_INDICATOR_VIA_DISPLAY_INFO, false)
+
+            // Re-create the repository, because the flag is read at init
+            underTest =
+                MobileConnectionRepositoryKairosImpl(
+                    SUB_1_ID,
+                    context,
+                    subscriptionModel,
+                    DEFAULT_NAME_MODEL,
+                    SEP,
+                    connectivityManager,
+                    telephonyManager,
+                    systemUiCarrierConfig,
+                    fakeBroadcastDispatcher,
+                    mobileMappings,
+                    testDispatcher,
+                    logger,
+                    tableLogger,
+                    flags,
+                    testScope.backgroundScope,
+                )
+
+            var latest: Boolean? = null
+            val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
+
+            val cb = getTelephonyCallbackForType<ServiceStateListener>()
+
+            // CDMA roaming is off, GSM roaming is off
+            whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_OFF)
+            cb.onServiceStateChanged(ServiceState().also { it.roaming = false })
+
+            assertThat(latest).isFalse()
+
+            // CDMA roaming is off, GSM roaming is on
+            cb.onServiceStateChanged(ServiceState().also { it.roaming = true })
+
+            assertThat(latest).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun activity_updatesFromCallback() =
+        testScope.runTest {
+            var latest: DataActivityModel? = null
+            val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest)
+                .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
+
+            val cb = getTelephonyCallbackForType<DataActivityListener>()
+            cb.onDataActivity(DATA_ACTIVITY_IN)
+            assertThat(latest)
+                .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = false))
+
+            cb.onDataActivity(DATA_ACTIVITY_OUT)
+            assertThat(latest)
+                .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = true))
+
+            cb.onDataActivity(DATA_ACTIVITY_INOUT)
+            assertThat(latest)
+                .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true))
+
+            cb.onDataActivity(DATA_ACTIVITY_NONE)
+            assertThat(latest)
+                .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
+
+            cb.onDataActivity(DATA_ACTIVITY_DORMANT)
+            assertThat(latest)
+                .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
+
+            cb.onDataActivity(1234)
+            assertThat(latest)
+                .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkNameForSubId_updates() =
+        testScope.runTest {
+            var latest: NetworkNameModel? = null
+            val job = underTest.carrierName.onEach { latest = it }.launchIn(this)
+
+            subscriptionModel.value =
+                SubscriptionModel(
+                    subscriptionId = SUB_1_ID,
+                    carrierName = DEFAULT_NAME,
+                    profileClass = PROFILE_CLASS_UNSET,
+                )
+
+            assertThat(latest?.name).isEqualTo(DEFAULT_NAME)
+
+            val updatedName = "Derived Carrier"
+            subscriptionModel.value =
+                SubscriptionModel(
+                    subscriptionId = SUB_1_ID,
+                    carrierName = updatedName,
+                    profileClass = PROFILE_CLASS_UNSET,
+                )
+
+            assertThat(latest?.name).isEqualTo(updatedName)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkNameForSubId_defaultWhenSubscriptionModelNull() =
+        testScope.runTest {
+            var latest: NetworkNameModel? = null
+            val job = underTest.carrierName.onEach { latest = it }.launchIn(this)
+
+            subscriptionModel.value = null
+
+            assertThat(latest?.name).isEqualTo(DEFAULT_NAME)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkName_default() =
+        testScope.runTest {
+            var latest: NetworkNameModel? = null
+            val job = underTest.networkName.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
+
+            job.cancel()
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_usesBroadcastInfo_returnsDerived() =
+        testScope.runTest {
+            var latest: NetworkNameModel? = null
+            val job = underTest.networkName.onEach { latest = it }.launchIn(this)
+
+            val intent = spnIntent()
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            captor.lastValue.onReceive(context, intent)
+
+            // spnIntent() sets all values to true and test strings
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+
+            job.cancel()
+        }
+
+    @Test
+    @DisableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_usesBroadcastInfo_returnsDerived_flagOff() =
+        testScope.runTest {
+            var latest: NetworkNameModel? = null
+            val job = underTest.networkName.onEach { latest = it }.launchIn(this)
+
+            val intent = spnIntent()
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            captor.lastValue.onReceive(context, intent)
+
+            // spnIntent() sets all values to true and test strings
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+
+            job.cancel()
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_broadcastNotForThisSubId_keepsOldValue() =
+        testScope.runTest {
+            var latest: NetworkNameModel? = null
+            val job = underTest.networkName.onEach { latest = it }.launchIn(this)
+
+            val intent = spnIntent()
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            captor.lastValue.onReceive(context, intent)
+
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+
+            // WHEN an intent with a different subId is sent
+            val wrongSubIntent = spnIntent(subId = 101)
+
+            captor.lastValue.onReceive(context, wrongSubIntent)
+
+            // THEN the previous intent's name is still used
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+
+            job.cancel()
+        }
+
+    @Test
+    @DisableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_broadcastNotForThisSubId_keepsOldValue_flagOff() =
+        testScope.runTest {
+            var latest: NetworkNameModel? = null
+            val job = underTest.networkName.onEach { latest = it }.launchIn(this)
+
+            val intent = spnIntent()
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            captor.lastValue.onReceive(context, intent)
+
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+
+            // WHEN an intent with a different subId is sent
+            val wrongSubIntent = spnIntent(subId = 101)
+
+            captor.lastValue.onReceive(context, wrongSubIntent)
+
+            // THEN the previous intent's name is still used
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+
+            job.cancel()
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_broadcastHasNoData_updatesToDefault() =
+        testScope.runTest {
+            var latest: NetworkNameModel? = null
+            val job = underTest.networkName.onEach { latest = it }.launchIn(this)
+
+            val intent = spnIntent()
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            captor.lastValue.onReceive(context, intent)
+
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+
+            val intentWithoutInfo = spnIntent(showSpn = false, showPlmn = false)
+
+            captor.lastValue.onReceive(context, intentWithoutInfo)
+
+            assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
+
+            job.cancel()
+        }
+
+    @Test
+    @DisableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_broadcastHasNoData_updatesToDefault_flagOff() =
+        testScope.runTest {
+            var latest: NetworkNameModel? = null
+            val job = underTest.networkName.onEach { latest = it }.launchIn(this)
+
+            val intent = spnIntent()
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            captor.lastValue.onReceive(context, intent)
+
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+
+            val intentWithoutInfo = spnIntent(showSpn = false, showPlmn = false)
+
+            captor.lastValue.onReceive(context, intentWithoutInfo)
+
+            assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
+
+            job.cancel()
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_usingEagerStrategy_retainsNameBetweenSubscribers() =
+        testScope.runTest {
+            // Use the [StateFlow.value] getter so we can prove that the collection happens
+            // even when there is no [Job]
+
+            // Starts out default
+            assertThat(underTest.networkName.value).isEqualTo(DEFAULT_NAME_MODEL)
+
+            val intent = spnIntent()
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            captor.lastValue.onReceive(context, intent)
+
+            // The value is still there despite no active subscribers
+            assertThat(underTest.networkName.value)
+                .isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+        }
+
+    @Test
+    @DisableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_usingEagerStrategy_retainsNameBetweenSubscribers_flagOff() =
+        testScope.runTest {
+            // Use the [StateFlow.value] getter so we can prove that the collection happens
+            // even when there is no [Job]
+
+            // Starts out default
+            assertThat(underTest.networkName.value).isEqualTo(DEFAULT_NAME_MODEL)
+
+            val intent = spnIntent()
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            captor.lastValue.onReceive(context, intent)
+
+            // The value is still there despite no active subscribers
+            assertThat(underTest.networkName.value)
+                .isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_allFieldsSet_prioritizesDataSpnOverSpn() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.networkName)
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+
+            val intent =
+                spnIntent(
+                    subId = SUB_1_ID,
+                    showSpn = true,
+                    spn = SPN,
+                    dataSpn = DATA_SPN,
+                    showPlmn = true,
+                    plmn = PLMN,
+                )
+            captor.lastValue.onReceive(context, intent)
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_spnAndPlmn_fallbackToSpnWhenNullDataSpn() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.networkName)
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+
+            val intent =
+                spnIntent(
+                    subId = SUB_1_ID,
+                    showSpn = true,
+                    spn = SPN,
+                    dataSpn = null,
+                    showPlmn = true,
+                    plmn = PLMN,
+                )
+            captor.lastValue.onReceive(context, intent)
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$SPN"))
+        }
+
+    @Test
+    @DisableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_allFieldsSet_flagOff() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.networkName)
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+
+            val intent =
+                spnIntent(
+                    subId = SUB_1_ID,
+                    showSpn = true,
+                    spn = SPN,
+                    dataSpn = DATA_SPN,
+                    showPlmn = true,
+                    plmn = PLMN,
+                )
+            captor.lastValue.onReceive(context, intent)
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_showPlmn_plmnNotNull_showSpn_spnNull_dataSpnNotNull() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.networkName)
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            val intent =
+                spnIntent(
+                    subId = SUB_1_ID,
+                    showSpn = true,
+                    spn = null,
+                    dataSpn = DATA_SPN,
+                    showPlmn = true,
+                    plmn = PLMN,
+                )
+            captor.lastValue.onReceive(context, intent)
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_showPlmn_plmnNotNull_showSpn_spnNotNull_dataSpnNull() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.networkName)
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            val intent =
+                spnIntent(
+                    subId = SUB_1_ID,
+                    showSpn = true,
+                    spn = SPN,
+                    dataSpn = null,
+                    showPlmn = true,
+                    plmn = PLMN,
+                )
+            captor.lastValue.onReceive(context, intent)
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$SPN"))
+        }
+
+    @Test
+    @DisableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_showPlmn_plmnNotNull_showSpn_spnNull_dataSpnNotNull_flagOff() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.networkName)
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            val intent =
+                spnIntent(
+                    subId = SUB_1_ID,
+                    showSpn = true,
+                    spn = null,
+                    dataSpn = DATA_SPN,
+                    showPlmn = true,
+                    plmn = PLMN,
+                )
+            captor.lastValue.onReceive(context, intent)
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+        }
+
+    @Test
+    fun networkName_showPlmn_noShowSPN() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.networkName)
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            val intent =
+                spnIntent(
+                    subId = SUB_1_ID,
+                    showSpn = false,
+                    spn = SPN,
+                    dataSpn = DATA_SPN,
+                    showPlmn = true,
+                    plmn = PLMN,
+                )
+            captor.lastValue.onReceive(context, intent)
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN"))
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_showPlmn_plmnNull_showSpn() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.networkName)
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            val intent =
+                spnIntent(
+                    subId = SUB_1_ID,
+                    showSpn = true,
+                    spn = SPN,
+                    dataSpn = DATA_SPN,
+                    showPlmn = true,
+                    plmn = null,
+                )
+            captor.lastValue.onReceive(context, intent)
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$DATA_SPN"))
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_showPlmn_plmnNull_showSpn_dataSpnNull() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.networkName)
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            val intent =
+                spnIntent(
+                    subId = SUB_1_ID,
+                    showSpn = true,
+                    spn = SPN,
+                    dataSpn = null,
+                    showPlmn = true,
+                    plmn = null,
+                )
+            captor.lastValue.onReceive(context, intent)
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$SPN"))
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_showPlmn_plmnNull_showSpn_bothSpnNull() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.networkName)
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            val intent =
+                spnIntent(
+                    subId = SUB_1_ID,
+                    showSpn = true,
+                    spn = null,
+                    dataSpn = null,
+                    showPlmn = true,
+                    plmn = null,
+                )
+            captor.lastValue.onReceive(context, intent)
+            assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
+        }
+
+    @Test
+    @DisableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_showPlmn_plmnNull_showSpn_flagOff() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.networkName)
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            val intent =
+                spnIntent(
+                    subId = SUB_1_ID,
+                    showSpn = true,
+                    spn = SPN,
+                    dataSpn = DATA_SPN,
+                    showPlmn = true,
+                    plmn = null,
+                )
+            captor.lastValue.onReceive(context, intent)
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$DATA_SPN"))
+        }
+
+    @Test
+    fun operatorAlphaShort_tracked() =
+        testScope.runTest {
+            var latest: String? = null
+
+            val job = underTest.operatorAlphaShort.onEach { latest = it }.launchIn(this)
+
+            val shortName = "short name"
+            val serviceState = ServiceState()
+            serviceState.setOperatorName(
+                /* longName */ "long name",
+                /* shortName */ shortName,
+                /* numeric */ "12345",
+            )
+
+            getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
+
+            assertThat(latest).isEqualTo(shortName)
+
+            job.cancel()
+        }
+
+    @Test
+    fun isInService_notIwlan() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isInService.onEach { latest = it }.launchIn(this)
+
+            val nriInService =
+                NetworkRegistrationInfo.Builder()
+                    .setDomain(DOMAIN_PS)
+                    .setTransportType(TRANSPORT_TYPE_WWAN)
+                    .setRegistrationState(REGISTRATION_STATE_HOME)
+                    .build()
+
+            getTelephonyCallbackForType<ServiceStateListener>()
+                .onServiceStateChanged(
+                    ServiceState().also {
+                        it.voiceRegState = STATE_IN_SERVICE
+                        it.addNetworkRegistrationInfo(nriInService)
+                    }
+                )
+
+            assertThat(latest).isTrue()
+
+            getTelephonyCallbackForType<ServiceStateListener>()
+                .onServiceStateChanged(
+                    ServiceState().also {
+                        it.voiceRegState = STATE_OUT_OF_SERVICE
+                        it.addNetworkRegistrationInfo(nriInService)
+                    }
+                )
+            assertThat(latest).isTrue()
+
+            val nriNotInService =
+                NetworkRegistrationInfo.Builder()
+                    .setDomain(DOMAIN_PS)
+                    .setTransportType(TRANSPORT_TYPE_WWAN)
+                    .setRegistrationState(REGISTRATION_STATE_DENIED)
+                    .build()
+            getTelephonyCallbackForType<ServiceStateListener>()
+                .onServiceStateChanged(
+                    ServiceState().also {
+                        it.voiceRegState = STATE_OUT_OF_SERVICE
+                        it.addNetworkRegistrationInfo(nriNotInService)
+                    }
+                )
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun isInService_isIwlan_voiceOutOfService_dataInService() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isInService.onEach { latest = it }.launchIn(this)
+
+            val iwlanData =
+                NetworkRegistrationInfo.Builder()
+                    .setDomain(DOMAIN_PS)
+                    .setTransportType(TRANSPORT_TYPE_WLAN)
+                    .setRegistrationState(REGISTRATION_STATE_HOME)
+                    .build()
+            val serviceState =
+                ServiceState().also {
+                    it.voiceRegState = STATE_OUT_OF_SERVICE
+                    it.addNetworkRegistrationInfo(iwlanData)
+                }
+
+            getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun isNonTerrestrial_updatesFromCallback0() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.isNonTerrestrial)
+
+            // Starts out false
+            assertThat(latest).isFalse()
+
+            val callback = getTelephonyCallbackForType<CarrierRoamingNtnListener>()
+
+            callback.onCarrierRoamingNtnModeChanged(true)
+            assertThat(latest).isTrue()
+
+            callback.onCarrierRoamingNtnModeChanged(false)
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun numberOfLevels_usesCarrierConfig() =
+        testScope.runTest {
+            var latest: Int? = null
+            val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS)
+
+            systemUiCarrierConfig.processNewCarrierConfig(
+                testCarrierConfigWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true)
+            )
+
+            assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS + 1)
+
+            systemUiCarrierConfig.processNewCarrierConfig(
+                testCarrierConfigWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
+            )
+
+            assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS)
+
+            job.cancel()
+        }
+
+    @Test
+    fun inflateSignalStrength_usesCarrierConfig() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.inflateSignalStrength)
+
+            assertThat(latest).isEqualTo(false)
+
+            systemUiCarrierConfig.processNewCarrierConfig(
+                testCarrierConfigWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true)
+            )
+
+            assertThat(latest).isEqualTo(true)
+
+            systemUiCarrierConfig.processNewCarrierConfig(
+                testCarrierConfigWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
+            )
+
+            assertThat(latest).isEqualTo(false)
+        }
+
+    @Test
+    fun allowNetworkSliceIndicator_exposesCarrierConfigValue() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.allowNetworkSliceIndicator)
+
+            systemUiCarrierConfig.processNewCarrierConfig(
+                testCarrierConfigWithOverride(KEY_SHOW_5G_SLICE_ICON_BOOL, true)
+            )
+
+            assertThat(latest).isTrue()
+
+            systemUiCarrierConfig.processNewCarrierConfig(
+                testCarrierConfigWithOverride(KEY_SHOW_5G_SLICE_ICON_BOOL, false)
+            )
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun isAllowedDuringAirplaneMode_alwaysFalse() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.isAllowedDuringAirplaneMode)
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun hasPrioritizedCaps_defaultFalse() {
+        assertThat(underTest.hasPrioritizedNetworkCapabilities.value).isFalse()
+    }
+
+    @Test
+    fun hasPrioritizedCaps_trueWhenAvailable() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.hasPrioritizedNetworkCapabilities)
+
+            val callback: NetworkCallback =
+                withArgCaptor<NetworkCallback> {
+                    verify(connectivityManager).registerNetworkCallback(any(), capture())
+                }
+
+            callback.onAvailable(mock())
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun hasPrioritizedCaps_becomesFalseWhenNetworkLost() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.hasPrioritizedNetworkCapabilities)
+
+            val callback: NetworkCallback =
+                withArgCaptor<NetworkCallback> {
+                    verify(connectivityManager).registerNetworkCallback(any(), capture())
+                }
+
+            callback.onAvailable(mock())
+
+            assertThat(latest).isTrue()
+
+            callback.onLost(mock())
+
+            assertThat(latest).isFalse()
+        }
+
+    private inline fun <reified T> getTelephonyCallbackForType(): T {
+        return MobileTelephonyHelpers.getTelephonyCallbackForType(telephonyManager)
+    }
+
+    private fun carrierIdIntent(subId: Int = SUB_1_ID, carrierId: Int): Intent =
+        Intent(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED).apply {
+            putExtra(EXTRA_SUBSCRIPTION_ID, subId)
+            putExtra(EXTRA_CARRIER_ID, carrierId)
+        }
+
+    private fun spnIntent(
+        subId: Int = SUB_1_ID,
+        showSpn: Boolean = true,
+        spn: String? = SPN,
+        dataSpn: String? = DATA_SPN,
+        showPlmn: Boolean = true,
+        plmn: String? = PLMN,
+    ): Intent =
+        Intent(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED).apply {
+            putExtra(EXTRA_SUBSCRIPTION_INDEX, subId)
+            putExtra(EXTRA_SHOW_SPN, showSpn)
+            putExtra(EXTRA_SPN, spn)
+            putExtra(EXTRA_DATA_SPN, dataSpn)
+            putExtra(EXTRA_SHOW_PLMN, showPlmn)
+            putExtra(EXTRA_PLMN, plmn)
+        }
+
+    companion object {
+        private const val SUB_1_ID = 1
+
+        private const val DEFAULT_NAME = "Fake Mobile Network"
+        private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
+        private const val SEP = "-"
+
+        private const val SPN = "testSpn"
+        private const val DATA_SPN = "testDataSpn"
+        private const val PLMN = "testPlmn"
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosTest.kt
new file mode 100644
index 0000000..85423218
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosTest.kt
@@ -0,0 +1,1622 @@
+/*
+ * Copyright (C) 2025 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.prod
+
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.net.ConnectivityManager
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
+import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import android.net.vcn.VcnTransportInfo
+import android.net.wifi.WifiInfo
+import android.net.wifi.WifiManager
+import android.os.ParcelUuid
+import android.telephony.CarrierConfigManager
+import android.telephony.ServiceState
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
+import android.telephony.TelephonyCallback
+import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
+import android.telephony.TelephonyManager
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.telephony.PhoneConstants
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.settingslib.R
+import com.android.settingslib.mobile.MobileMappings
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.table.TableLogBufferFactory
+import com.android.systemui.log.table.logcatTableLogBuffer
+import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
+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
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
+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.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.time.FakeSystemClock
+import com.android.wifitrackerlib.MergedCarrierEntry
+import com.android.wifitrackerlib.WifiEntry
+import com.android.wifitrackerlib.WifiPickerTracker
+import com.google.common.truth.Truth.assertThat
+import java.util.UUID
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Test
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@SmallTest
+// This is required because our [SubscriptionManager.OnSubscriptionsChangedListener] uses a looper
+// to run the callback and this makes the looper place nicely with TestScope etc.
+@TestableLooper.RunWithLooper
+class MobileConnectionsRepositoryKairosTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    private val flags =
+        FakeFeatureFlagsClassic().also { it.set(Flags.ROAMING_INDICATOR_VIA_DISPLAY_INFO, true) }
+
+    private lateinit var connectionFactory: MobileConnectionRepositoryImpl.Factory
+    private lateinit var carrierMergedFactory: CarrierMergedConnectionRepository.Factory
+    private lateinit var fullConnectionFactory: FullMobileConnectionRepository.Factory
+    private lateinit var connectivityRepository: ConnectivityRepository
+    private lateinit var airplaneModeRepository: FakeAirplaneModeRepository
+    private lateinit var wifiRepository: WifiRepository
+    private lateinit var carrierConfigRepository: CarrierConfigRepository
+
+    @Mock private lateinit var connectivityManager: ConnectivityManager
+    @Mock private lateinit var subscriptionManager: SubscriptionManager
+    @Mock private lateinit var telephonyManager: TelephonyManager
+    @Mock private lateinit var logger: MobileInputLogger
+    private val summaryLogger = logcatTableLogBuffer(kosmos, "summaryLogger")
+    @Mock private lateinit var logBufferFactory: TableLogBufferFactory
+    @Mock private lateinit var updateMonitor: KeyguardUpdateMonitor
+    @Mock private lateinit var wifiManager: WifiManager
+    @Mock private lateinit var wifiPickerTrackerFactory: WifiPickerTrackerFactory
+    @Mock private lateinit var wifiPickerTracker: WifiPickerTracker
+    private val wifiTableLogBuffer = logcatTableLogBuffer(kosmos, "wifiTableLog")
+
+    private val mobileMappings = FakeMobileMappingsProxy()
+    private val subscriptionManagerProxy = FakeSubscriptionManagerProxy()
+    private val mainExecutor = FakeExecutor(FakeSystemClock())
+    private val wifiLogBuffer = LogBuffer("wifi", maxSize = 100, logcatEchoTracker = mock())
+    private val wifiPickerTrackerCallback =
+        argumentCaptor<WifiPickerTracker.WifiPickerTrackerCallback>()
+    private val vcnTransportInfo = VcnTransportInfo.Builder().build()
+    private val userRepository = kosmos.fakeUserRepository
+
+    private val testDispatcher = StandardTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+
+    private lateinit var underTest: MobileConnectionsRepositoryKairosImpl
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        whenever(telephonyManager.simOperatorName).thenReturn("")
+
+        // Set up so the individual connection repositories
+        whenever(telephonyManager.createForSubscriptionId(anyInt())).thenAnswer { invocation ->
+            telephonyManager.also {
+                whenever(it.subscriptionId).thenReturn(invocation.getArgument(0))
+            }
+        }
+
+        whenever(logBufferFactory.getOrCreate(anyString(), anyInt())).thenAnswer { _ ->
+            logcatTableLogBuffer(kosmos, "test")
+        }
+
+        whenever(
+                wifiPickerTrackerFactory.create(
+                    any(),
+                    any(),
+                    capture(wifiPickerTrackerCallback),
+                    any(),
+                )
+            )
+            .thenReturn(wifiPickerTracker)
+
+        // For convenience, set up the subscription info callbacks
+        whenever(subscriptionManager.getActiveSubscriptionInfo(anyInt())).thenAnswer { invocation ->
+            when (invocation.getArgument(0) as Int) {
+                1 -> SUB_1
+                2 -> SUB_2
+                3 -> SUB_3
+                4 -> SUB_4
+                else -> null
+            }
+        }
+
+        connectivityRepository =
+            ConnectivityRepositoryImpl(
+                connectivityManager,
+                ConnectivitySlots(context),
+                context,
+                mock(),
+                mock(),
+                testScope.backgroundScope,
+                mock(),
+            )
+
+        airplaneModeRepository = FakeAirplaneModeRepository()
+
+        wifiRepository =
+            WifiRepositoryImpl(
+                mContext,
+                userRepository,
+                testScope.backgroundScope,
+                mainExecutor,
+                testDispatcher,
+                wifiPickerTrackerFactory,
+                wifiManager,
+                wifiLogBuffer,
+                wifiTableLogBuffer,
+            )
+
+        carrierConfigRepository = kosmos.carrierConfigRepository
+
+        connectionFactory =
+            MobileConnectionRepositoryImpl.Factory(
+                context,
+                fakeBroadcastDispatcher,
+                connectivityManager,
+                telephonyManager = telephonyManager,
+                bgDispatcher = testDispatcher,
+                logger = logger,
+                mobileMappingsProxy = mobileMappings,
+                scope = testScope.backgroundScope,
+                flags = flags,
+                carrierConfigRepository = carrierConfigRepository,
+            )
+        carrierMergedFactory =
+            CarrierMergedConnectionRepository.Factory(
+                telephonyManager,
+                testScope.backgroundScope.coroutineContext,
+                testScope.backgroundScope,
+                wifiRepository,
+            )
+        fullConnectionFactory =
+            FullMobileConnectionRepository.Factory(
+                scope = testScope.backgroundScope,
+                logFactory = logBufferFactory,
+                mobileRepoFactory = connectionFactory,
+                carrierMergedRepoFactory = carrierMergedFactory,
+            )
+
+        underTest =
+            MobileConnectionsRepositoryKairosImpl(
+                connectivityRepository,
+                subscriptionManager,
+                subscriptionManagerProxy,
+                telephonyManager,
+                logger,
+                summaryLogger,
+                mobileMappings,
+                fakeBroadcastDispatcher,
+                context,
+                /* bgDispatcher = */ testDispatcher,
+                testScope.backgroundScope,
+                /* mainDispatcher = */ testDispatcher,
+                airplaneModeRepository,
+                wifiRepository,
+                fullConnectionFactory,
+                updateMonitor,
+                mock(),
+            )
+
+        testScope.runCurrent()
+    }
+
+    @Test
+    fun testSubscriptions_initiallyEmpty() =
+        testScope.runTest {
+            assertThat(underTest.subscriptions.value).isEqualTo(listOf<SubscriptionModel>())
+        }
+
+    @Test
+    fun testSubscriptions_listUpdates() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.subscriptions)
+
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1, SUB_2))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            assertThat(latest).isEqualTo(listOf(MODEL_1, MODEL_2))
+        }
+
+    @Test
+    fun testSubscriptions_removingSub_updatesList() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.subscriptions)
+
+            // WHEN 2 networks show up
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1, SUB_2))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            // WHEN one network is removed
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_2))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            // THEN the subscriptions list represents the newest change
+            assertThat(latest).isEqualTo(listOf(MODEL_2))
+        }
+
+    @Test
+    fun subscriptions_subIsOnlyNtn_modelHasExclusivelyNtnTrue() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.subscriptions)
+
+            val onlyNtnSub =
+                mock<SubscriptionInfo>().also {
+                    whenever(it.isOnlyNonTerrestrialNetwork).thenReturn(true)
+                    whenever(it.subscriptionId).thenReturn(45)
+                    whenever(it.groupUuid).thenReturn(GROUP_1)
+                    whenever(it.carrierName).thenReturn("NTN only")
+                    whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
+                }
+
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(onlyNtnSub))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            assertThat(latest).hasSize(1)
+            assertThat(latest!![0].isExclusivelyNonTerrestrial).isTrue()
+        }
+
+    @Test
+    fun subscriptions_subIsNotOnlyNtn_modelHasExclusivelyNtnFalse() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.subscriptions)
+
+            val notOnlyNtnSub =
+                mock<SubscriptionInfo>().also {
+                    whenever(it.isOnlyNonTerrestrialNetwork).thenReturn(false)
+                    whenever(it.subscriptionId).thenReturn(45)
+                    whenever(it.groupUuid).thenReturn(GROUP_1)
+                    whenever(it.carrierName).thenReturn("NTN only")
+                    whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
+                }
+
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(notOnlyNtnSub))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            assertThat(latest).hasSize(1)
+            assertThat(latest!![0].isExclusivelyNonTerrestrial).isFalse()
+        }
+
+    @Test
+    fun testSubscriptions_carrierMergedOnly_listHasCarrierMerged() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.subscriptions)
+
+            setWifiState(isCarrierMerged = true)
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_CM))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            assertThat(latest).isEqualTo(listOf(MODEL_CM))
+        }
+
+    @Test
+    fun testSubscriptions_carrierMergedAndOther_listHasBothWithCarrierMergedLast() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.subscriptions)
+
+            setWifiState(isCarrierMerged = true)
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1, SUB_2, SUB_CM))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            assertThat(latest).isEqualTo(listOf(MODEL_1, MODEL_2, MODEL_CM))
+        }
+
+    @Test
+    fun testActiveDataSubscriptionId_initialValueIsNull() =
+        testScope.runTest {
+            assertThat(underTest.activeMobileDataSubscriptionId.value).isEqualTo(null)
+        }
+
+    @Test
+    fun testActiveDataSubscriptionId_updates() =
+        testScope.runTest {
+            val active by collectLastValue(underTest.activeMobileDataSubscriptionId)
+
+            getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+                .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+
+            assertThat(active).isEqualTo(SUB_2_ID)
+        }
+
+    @Test
+    fun activeSubId_nullIfInvalidSubIdIsReceived() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.activeMobileDataSubscriptionId)
+
+            getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+                .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+
+            assertThat(latest).isNotNull()
+
+            getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+                .onActiveDataSubscriptionIdChanged(INVALID_SUBSCRIPTION_ID)
+
+            assertThat(latest).isNull()
+        }
+
+    @Test
+    fun activeRepo_initiallyNull() {
+        assertThat(underTest.activeMobileDataRepository.value).isNull()
+    }
+
+    @Test
+    fun activeRepo_updatesWithActiveDataId() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.activeMobileDataRepository)
+
+            getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+                .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+
+            assertThat(latest?.subId).isEqualTo(SUB_2_ID)
+        }
+
+    @Test
+    fun activeRepo_nullIfActiveDataSubIdBecomesInvalid() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.activeMobileDataRepository)
+
+            getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+                .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+
+            assertThat(latest).isNotNull()
+
+            getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+                .onActiveDataSubscriptionIdChanged(INVALID_SUBSCRIPTION_ID)
+
+            assertThat(latest).isNull()
+        }
+
+    @Test
+    /** Regression test for b/268146648. */
+    fun activeSubIdIsSetBeforeSubscriptionsAreUpdated_doesNotThrow() =
+        testScope.runTest {
+            val activeRepo by collectLastValue(underTest.activeMobileDataRepository)
+            val subscriptions by collectLastValue(underTest.subscriptions)
+
+            getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+                .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+
+            assertThat(subscriptions).isEmpty()
+            assertThat(activeRepo).isNotNull()
+        }
+
+    @Test
+    fun getRepoForSubId_activeDataSubIdIsRequestedBeforeSubscriptionsUpdate() =
+        testScope.runTest {
+            var latestActiveRepo: MobileConnectionRepository? = null
+            collectLastValue(
+                underTest.activeMobileDataSubscriptionId.filterNotNull().onEach {
+                    latestActiveRepo = underTest.getRepoForSubId(it)
+                }
+            )
+
+            val latestSubscriptions by collectLastValue(underTest.subscriptions)
+
+            // Active data subscription id is sent, but no subscription change has been posted yet
+            getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+                .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+
+            // Subscriptions list is empty
+            assertThat(latestSubscriptions).isEmpty()
+            // getRepoForSubId does not throw
+            assertThat(latestActiveRepo).isNotNull()
+        }
+
+    @Test
+    fun activeDataSentBeforeSubscriptionList_subscriptionReusesActiveDataRepo() =
+        testScope.runTest {
+            val activeRepo by collectLastValue(underTest.activeMobileDataRepository)
+            collectLastValue(underTest.subscriptions)
+
+            // GIVEN active repo is updated before the subscription list updates
+            getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+                .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+
+            assertThat(activeRepo).isNotNull()
+
+            // GIVEN the subscription list is then updated which includes the active data sub id
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_2))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            // WHEN requesting a connection repository for the subscription
+            val newRepo = underTest.getRepoForSubId(SUB_2_ID)
+
+            // THEN the newly request repo has been cached and reused
+            assertThat(activeRepo).isSameInstanceAs(newRepo)
+        }
+
+    @Test
+    fun testConnectionRepository_validSubId_isCached() =
+        testScope.runTest {
+            collectLastValue(underTest.subscriptions)
+
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            val repo1 = underTest.getRepoForSubId(SUB_1_ID)
+            val repo2 = underTest.getRepoForSubId(SUB_1_ID)
+
+            assertThat(repo1).isSameInstanceAs(repo2)
+        }
+
+    @Test
+    fun testConnectionRepository_carrierMergedSubId_isCached() =
+        testScope.runTest {
+            collectLastValue(underTest.subscriptions)
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+            setWifiState(isCarrierMerged = true)
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_CM))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            val repo1 = underTest.getRepoForSubId(SUB_CM_ID)
+            val repo2 = underTest.getRepoForSubId(SUB_CM_ID)
+
+            assertThat(repo1).isSameInstanceAs(repo2)
+        }
+
+    @Test
+    fun testConnectionRepository_carrierMergedAndMobileSubs_usesCorrectRepos() =
+        testScope.runTest {
+            collectLastValue(underTest.subscriptions)
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+            setWifiState(isCarrierMerged = true)
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1, SUB_CM))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            val carrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
+            val mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
+            assertThat(carrierMergedRepo.getIsCarrierMerged()).isTrue()
+            assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
+        }
+
+    @Test
+    fun testSubscriptions_subNoLongerCarrierMerged_repoUpdates() =
+        testScope.runTest {
+            collectLastValue(underTest.subscriptions)
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+            setWifiState(isCarrierMerged = true)
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1, SUB_CM))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            val carrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
+            var mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
+            assertThat(carrierMergedRepo.getIsCarrierMerged()).isTrue()
+            assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
+
+            // WHEN the wifi network updates to be not carrier merged
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_ACTIVE)
+            setWifiState(isCarrierMerged = false)
+            runCurrent()
+
+            // THEN the repos update
+            val noLongerCarrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
+            mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
+            assertThat(noLongerCarrierMergedRepo.getIsCarrierMerged()).isFalse()
+            assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
+        }
+
+    @Test
+    fun testSubscriptions_subBecomesCarrierMerged_repoUpdates() =
+        testScope.runTest {
+            collectLastValue(underTest.subscriptions)
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_ACTIVE)
+            setWifiState(isCarrierMerged = false)
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1, SUB_CM))
+            getSubscriptionCallback().onSubscriptionsChanged()
+            runCurrent()
+
+            val notYetCarrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
+            var mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
+            assertThat(notYetCarrierMergedRepo.getIsCarrierMerged()).isFalse()
+            assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
+
+            // WHEN the wifi network updates to be carrier merged
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+            setWifiState(isCarrierMerged = true)
+            runCurrent()
+
+            // THEN the repos update
+            val carrierMergedRepo = underTest.getRepoForSubId(SUB_CM_ID)
+            mobileRepo = underTest.getRepoForSubId(SUB_1_ID)
+            assertThat(carrierMergedRepo.getIsCarrierMerged()).isTrue()
+            assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
+        }
+
+    @SuppressLint("UnspecifiedRegisterReceiverFlag")
+    @Test
+    fun testDeviceEmergencyCallState_eagerlyChecksState() =
+        testScope.runTest {
+            // Value starts out false
+            assertThat(underTest.isDeviceEmergencyCallCapable.value).isFalse()
+            whenever(telephonyManager.activeModemCount).thenReturn(1)
+            whenever(telephonyManager.getServiceStateForSlot(any())).thenAnswer { _ ->
+                ServiceState().apply { isEmergencyOnly = true }
+            }
+
+            // WHEN an appropriate intent gets sent out
+            val intent = serviceStateIntent(subId = -1)
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent)
+            runCurrent()
+
+            // THEN the repo's state is updated despite no listeners
+            assertThat(underTest.isDeviceEmergencyCallCapable.value).isEqualTo(true)
+        }
+
+    @Test
+    fun testDeviceEmergencyCallState_aggregatesAcrossSlots_oneTrue() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.isDeviceEmergencyCallCapable)
+
+            // GIVEN there are multiple slots
+            whenever(telephonyManager.activeModemCount).thenReturn(4)
+            // GIVEN only one of them reports ECM
+            whenever(telephonyManager.getServiceStateForSlot(any())).thenAnswer { invocation ->
+                when (invocation.getArgument(0) as Int) {
+                    0 -> ServiceState().apply { isEmergencyOnly = false }
+                    1 -> ServiceState().apply { isEmergencyOnly = false }
+                    2 -> ServiceState().apply { isEmergencyOnly = true }
+                    3 -> ServiceState().apply { isEmergencyOnly = false }
+                    else -> null
+                }
+            }
+
+            // GIVEN a broadcast goes out for the appropriate subID
+            val intent = serviceStateIntent(subId = -1)
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent)
+            runCurrent()
+
+            // THEN the device is in ECM, because one of the service states is
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun testDeviceEmergencyCallState_aggregatesAcrossSlots_allFalse() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.isDeviceEmergencyCallCapable)
+
+            // GIVEN there are multiple slots
+            whenever(telephonyManager.activeModemCount).thenReturn(4)
+            // GIVEN only one of them reports ECM
+            whenever(telephonyManager.getServiceStateForSlot(any())).thenAnswer { invocation ->
+                when (invocation.getArgument(0) as Int) {
+                    0 -> ServiceState().apply { isEmergencyOnly = false }
+                    1 -> ServiceState().apply { isEmergencyOnly = false }
+                    2 -> ServiceState().apply { isEmergencyOnly = false }
+                    3 -> ServiceState().apply { isEmergencyOnly = false }
+                    else -> null
+                }
+            }
+
+            // GIVEN a broadcast goes out for the appropriate subID
+            val intent = serviceStateIntent(subId = -1)
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent)
+            runCurrent()
+
+            // THEN the device is in ECM, because one of the service states is
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    @Ignore("b/333912012")
+    fun testConnectionCache_clearsInvalidSubscriptions() =
+        testScope.runTest {
+            collectLastValue(underTest.subscriptions)
+
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1, SUB_2))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            // Get repos to trigger caching
+            val repo1 = underTest.getRepoForSubId(SUB_1_ID)
+            val repo2 = underTest.getRepoForSubId(SUB_2_ID)
+
+            assertThat(underTest.getSubIdRepoCache())
+                .containsExactly(SUB_1_ID, repo1, SUB_2_ID, repo2)
+
+            // SUB_2 disappears
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            assertThat(underTest.getSubIdRepoCache()).containsExactly(SUB_1_ID, repo1)
+        }
+
+    @Test
+    @Ignore("b/333912012")
+    fun testConnectionCache_clearsInvalidSubscriptions_includingCarrierMerged() =
+        testScope.runTest {
+            collectLastValue(underTest.subscriptions)
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+            setWifiState(isCarrierMerged = true)
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1, SUB_2, SUB_CM))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            // Get repos to trigger caching
+            val repo1 = underTest.getRepoForSubId(SUB_1_ID)
+            val repo2 = underTest.getRepoForSubId(SUB_2_ID)
+            val repoCarrierMerged = underTest.getRepoForSubId(SUB_CM_ID)
+
+            assertThat(underTest.getSubIdRepoCache())
+                .containsExactly(SUB_1_ID, repo1, SUB_2_ID, repo2, SUB_CM_ID, repoCarrierMerged)
+
+            // SUB_2 and SUB_CM disappear
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            assertThat(underTest.getSubIdRepoCache()).containsExactly(SUB_1_ID, repo1)
+        }
+
+    /** Regression test for b/261706421 */
+    @Test
+    @Ignore("b/333912012")
+    fun testConnectionsCache_clearMultipleSubscriptionsAtOnce_doesNotThrow() =
+        testScope.runTest {
+            collectLastValue(underTest.subscriptions)
+
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1, SUB_2))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            // Get repos to trigger caching
+            val repo1 = underTest.getRepoForSubId(SUB_1_ID)
+            val repo2 = underTest.getRepoForSubId(SUB_2_ID)
+
+            assertThat(underTest.getSubIdRepoCache())
+                .containsExactly(SUB_1_ID, repo1, SUB_2_ID, repo2)
+
+            // All subscriptions disappear
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList).thenReturn(listOf())
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            assertThat(underTest.getSubIdRepoCache()).isEmpty()
+        }
+
+    @Test
+    fun testConnectionsCache_keepsReposCached() =
+        testScope.runTest {
+            // Collect subscriptions to start the job
+            collectLastValue(underTest.subscriptions)
+
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            val repo1_1 = underTest.getRepoForSubId(SUB_1_ID)
+
+            // All subscriptions disappear
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList).thenReturn(listOf())
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            // Sub1 comes back
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            val repo1_2 = underTest.getRepoForSubId(SUB_1_ID)
+
+            assertThat(repo1_1).isSameInstanceAs(repo1_2)
+        }
+
+    @Test
+    fun testConnectionsCache_doesNotDropReferencesThatHaveBeenRealized() =
+        testScope.runTest {
+            // Collect subscriptions to start the job
+            collectLastValue(underTest.subscriptions)
+
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            // Client grabs a reference to a repository, but doesn't keep it around
+            underTest.getRepoForSubId(SUB_1_ID)
+
+            // All subscriptions disappear
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList).thenReturn(listOf())
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            val repo1 = underTest.getRepoForSubId(SUB_1_ID)
+
+            assertThat(repo1).isNotNull()
+        }
+
+    @Test
+    fun testConnectionRepository_invalidSubId_doesNotThrow() =
+        testScope.runTest {
+            underTest.getRepoForSubId(SUB_1_ID)
+            // No exception
+        }
+
+    @Test
+    fun connectionRepository_logBufferContainsSubIdInItsName() =
+        testScope.runTest {
+            collectLastValue(underTest.subscriptions)
+
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1, SUB_2))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            // Get repos to trigger creation
+            underTest.getRepoForSubId(SUB_1_ID)
+            verify(logBufferFactory).getOrCreate(eq(tableBufferLogName(SUB_1_ID)), anyInt())
+            underTest.getRepoForSubId(SUB_2_ID)
+            verify(logBufferFactory).getOrCreate(eq(tableBufferLogName(SUB_2_ID)), anyInt())
+        }
+
+    @Test
+    fun testDefaultDataSubId_updatesOnBroadcast() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.defaultDataSubId)
+
+            assertThat(latest).isEqualTo(null)
+
+            val intent2 =
+                Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+                    .putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_2_ID)
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent2)
+
+            assertThat(latest).isEqualTo(SUB_2_ID)
+
+            val intent1 =
+                Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+                    .putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_1_ID)
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent1)
+
+            assertThat(latest).isEqualTo(SUB_1_ID)
+        }
+
+    @Test
+    fun defaultDataSubId_fetchesInitialValueOnStart() =
+        testScope.runTest {
+            subscriptionManagerProxy.defaultDataSubId = 2
+            val latest by collectLastValue(underTest.defaultDataSubId)
+
+            assertThat(latest).isEqualTo(2)
+        }
+
+    @Test
+    fun defaultDataSubId_filtersOutInvalidSubIds() =
+        testScope.runTest {
+            subscriptionManagerProxy.defaultDataSubId = INVALID_SUBSCRIPTION_ID
+            val latest by collectLastValue(underTest.defaultDataSubId)
+
+            assertThat(latest).isNull()
+        }
+
+    @Test
+    fun defaultDataSubId_filtersOutInvalidSubIds_fromValidToInvalid() =
+        testScope.runTest {
+            subscriptionManagerProxy.defaultDataSubId = 2
+            val latest by collectLastValue(underTest.defaultDataSubId)
+
+            assertThat(latest).isEqualTo(2)
+
+            val intent =
+                Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+                    .putExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID)
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent)
+
+            assertThat(latest).isNull()
+        }
+
+    @Test
+    fun defaultDataSubId_fetchesCurrentOnRestart() =
+        testScope.runTest {
+            subscriptionManagerProxy.defaultDataSubId = 2
+            var latest: Int? = null
+            var job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this)
+            runCurrent()
+
+            assertThat(latest).isEqualTo(2)
+
+            job.cancel()
+
+            // Collectors go away but come back later
+
+            latest = null
+
+            subscriptionManagerProxy.defaultDataSubId = 1
+
+            job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this)
+            runCurrent()
+
+            assertThat(latest).isEqualTo(1)
+
+            job.cancel()
+        }
+
+    @Test
+    fun mobileIsDefault_startsAsFalse() {
+        assertThat(underTest.mobileIsDefault.value).isFalse()
+    }
+
+    @Test
+    fun mobileIsDefault_capsHaveCellular_isDefault() =
+        testScope.runTest {
+            val caps =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+                }
+
+            val latest by collectLastValue(underTest.mobileIsDefault)
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun mobileIsDefault_capsDoNotHaveCellular_isNotDefault() =
+        testScope.runTest {
+            val caps =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false)
+                }
+
+            val latest by collectLastValue(underTest.mobileIsDefault)
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun mobileIsDefault_carrierMergedViaMobile_isDefault() =
+        testScope.runTest {
+            val carrierMergedInfo =
+                mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(true) }
+            val caps =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+                    whenever(it.transportInfo).thenReturn(carrierMergedInfo)
+                }
+
+            val latest by collectLastValue(underTest.mobileIsDefault)
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun mobileIsDefault_wifiDefault_mobileNotDefault() =
+        testScope.runTest {
+            val caps =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+                }
+
+            val latest by collectLastValue(underTest.mobileIsDefault)
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun mobileIsDefault_ethernetDefault_mobileNotDefault() =
+        testScope.runTest {
+            val caps =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasTransport(TRANSPORT_ETHERNET)).thenReturn(true)
+                }
+
+            val latest by collectLastValue(underTest.mobileIsDefault)
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+            assertThat(latest).isFalse()
+        }
+
+    /** Regression test for b/272586234. */
+    @Test
+    fun hasCarrierMergedConnection_carrierMergedViaWifi_isTrue() =
+        testScope.runTest {
+            val carrierMergedInfo =
+                mock<WifiInfo>().apply {
+                    whenever(this.isCarrierMerged).thenReturn(true)
+                    whenever(this.isPrimary).thenReturn(true)
+                }
+            val caps =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+                    whenever(it.transportInfo).thenReturn(carrierMergedInfo)
+                }
+
+            val latest by collectLastValue(underTest.hasCarrierMergedConnection)
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+            setWifiState(isCarrierMerged = true)
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun hasCarrierMergedConnection_carrierMergedViaMobile_isTrue() =
+        testScope.runTest {
+            val carrierMergedInfo =
+                mock<WifiInfo>().apply {
+                    whenever(this.isCarrierMerged).thenReturn(true)
+                    whenever(this.isPrimary).thenReturn(true)
+                }
+            val caps =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+                    whenever(it.transportInfo).thenReturn(carrierMergedInfo)
+                }
+
+            val latest by collectLastValue(underTest.hasCarrierMergedConnection)
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+            setWifiState(isCarrierMerged = true)
+
+            assertThat(latest).isTrue()
+        }
+
+    private fun newWifiNetwork(wifiInfo: WifiInfo): Network {
+        val network = mock<Network>()
+        val capabilities =
+            mock<NetworkCapabilities>().also {
+                whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+                whenever(it.transportInfo).thenReturn(wifiInfo)
+            }
+        whenever(connectivityManager.getNetworkCapabilities(network)).thenReturn(capabilities)
+
+        return network
+    }
+
+    /** Regression test for b/272586234. */
+    @Test
+    fun hasCarrierMergedConnection_carrierMergedViaWifiWithVcnTransport_isTrue() =
+        testScope.runTest {
+            val carrierMergedInfo =
+                mock<WifiInfo>().apply {
+                    whenever(this.isCarrierMerged).thenReturn(true)
+                    whenever(this.isPrimary).thenReturn(true)
+                }
+            val underlyingWifi = newWifiNetwork(carrierMergedInfo)
+            val caps =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+                    whenever(it.transportInfo).thenReturn(vcnTransportInfo)
+                    whenever(it.underlyingNetworks).thenReturn(listOf(underlyingWifi))
+                }
+
+            val latest by collectLastValue(underTest.hasCarrierMergedConnection)
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+            setWifiState(isCarrierMerged = true)
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun hasCarrierMergedConnection_carrierMergedViaMobileWithVcnTransport_isTrue() =
+        testScope.runTest {
+            val carrierMergedInfo =
+                mock<WifiInfo>().apply {
+                    whenever(this.isCarrierMerged).thenReturn(true)
+                    whenever(this.isPrimary).thenReturn(true)
+                }
+            val underlyingWifi = newWifiNetwork(carrierMergedInfo)
+            val caps =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+                    whenever(it.transportInfo).thenReturn(vcnTransportInfo)
+                    whenever(it.underlyingNetworks).thenReturn(listOf(underlyingWifi))
+                }
+
+            val latest by collectLastValue(underTest.hasCarrierMergedConnection)
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+            setWifiState(isCarrierMerged = true)
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun hasCarrierMergedConnection_isCarrierMergedViaUnderlyingWifi_isTrue() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.hasCarrierMergedConnection)
+
+            val underlyingNetwork = mock<Network>()
+            val carrierMergedInfo =
+                mock<WifiInfo>().apply {
+                    whenever(this.isCarrierMerged).thenReturn(true)
+                    whenever(this.isPrimary).thenReturn(true)
+                }
+            val underlyingWifiCapabilities =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+                    whenever(it.transportInfo).thenReturn(carrierMergedInfo)
+                }
+            whenever(connectivityManager.getNetworkCapabilities(underlyingNetwork))
+                .thenReturn(underlyingWifiCapabilities)
+
+            // WHEN the main capabilities have an underlying carrier merged network via WIFI
+            // transport and WifiInfo
+            val mainCapabilities =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+                    whenever(it.transportInfo).thenReturn(null)
+                    whenever(it.underlyingNetworks).thenReturn(listOf(underlyingNetwork))
+                }
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities)
+            setWifiState(isCarrierMerged = true)
+
+            // THEN there's a carrier merged connection
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun hasCarrierMergedConnection_isCarrierMergedViaUnderlyingCellular_isTrue() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.hasCarrierMergedConnection)
+
+            val underlyingCarrierMergedNetwork = mock<Network>()
+            val carrierMergedInfo =
+                mock<WifiInfo>().apply {
+                    whenever(this.isCarrierMerged).thenReturn(true)
+                    whenever(this.isPrimary).thenReturn(true)
+                }
+
+            // The Wifi network that is under the VCN network
+            val physicalWifiNetwork = newWifiNetwork(carrierMergedInfo)
+
+            val underlyingCapabilities =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+                    whenever(it.transportInfo).thenReturn(vcnTransportInfo)
+                    whenever(it.underlyingNetworks).thenReturn(listOf(physicalWifiNetwork))
+                }
+            whenever(connectivityManager.getNetworkCapabilities(underlyingCarrierMergedNetwork))
+                .thenReturn(underlyingCapabilities)
+
+            // WHEN the main capabilities have an underlying carrier merged network via CELLULAR
+            // transport and VcnTransportInfo
+            val mainCapabilities =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+                    whenever(it.transportInfo).thenReturn(null)
+                    whenever(it.underlyingNetworks)
+                        .thenReturn(listOf(underlyingCarrierMergedNetwork))
+                }
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities)
+            setWifiState(isCarrierMerged = true)
+
+            // THEN there's a carrier merged connection
+            assertThat(latest).isTrue()
+        }
+
+    /** Regression test for b/272586234. */
+    @Test
+    fun hasCarrierMergedConnection_defaultIsWifiNotCarrierMerged_wifiRepoIsCarrierMerged_isTrue() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.hasCarrierMergedConnection)
+
+            // WHEN the default callback is TRANSPORT_WIFI but not carrier merged
+            val carrierMergedInfo =
+                mock<WifiInfo>().apply { whenever(this.isCarrierMerged).thenReturn(false) }
+            val caps =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+                    whenever(it.transportInfo).thenReturn(carrierMergedInfo)
+                }
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+            // BUT the wifi repo has gotten updates that it *is* carrier merged
+            setWifiState(isCarrierMerged = true)
+
+            // THEN hasCarrierMergedConnection is true
+            assertThat(latest).isTrue()
+        }
+
+    /** Regression test for b/278618530. */
+    @Test
+    fun hasCarrierMergedConnection_defaultIsCellular_wifiRepoIsCarrierMerged_isFalse() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.hasCarrierMergedConnection)
+
+            // WHEN the default callback is TRANSPORT_CELLULAR and not carrier merged
+            val caps =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+                    whenever(it.transportInfo).thenReturn(null)
+                }
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+            // BUT the wifi repo has gotten updates that it *is* carrier merged
+            setWifiState(isCarrierMerged = true)
+
+            // THEN hasCarrierMergedConnection is **false** (The default network being CELLULAR
+            // takes precedence over the wifi network being carrier merged.)
+            assertThat(latest).isFalse()
+        }
+
+    /** Regression test for b/278618530. */
+    @Test
+    fun hasCarrierMergedConnection_defaultCellular_wifiIsCarrierMerged_airplaneMode_isTrue() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.hasCarrierMergedConnection)
+
+            // WHEN the default callback is TRANSPORT_CELLULAR and not carrier merged
+            val caps =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+                    whenever(it.transportInfo).thenReturn(null)
+                }
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+            // BUT the wifi repo has gotten updates that it *is* carrier merged
+            setWifiState(isCarrierMerged = true)
+            // AND we're in airplane mode
+            airplaneModeRepository.setIsAirplaneMode(true)
+
+            // THEN hasCarrierMergedConnection is true.
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun defaultConnectionIsValidated_startsAsFalse() {
+        assertThat(underTest.defaultConnectionIsValidated.value).isFalse()
+    }
+
+    @Test
+    fun defaultConnectionIsValidated_capsHaveValidated_isValidated() =
+        testScope.runTest {
+            val caps =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasCapability(NET_CAPABILITY_VALIDATED)).thenReturn(true)
+                }
+
+            val latest by collectLastValue(underTest.defaultConnectionIsValidated)
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun defaultConnectionIsValidated_capsHaveNotValidated_isNotValidated() =
+        testScope.runTest {
+            val caps =
+                mock<NetworkCapabilities>().also {
+                    whenever(it.hasCapability(NET_CAPABILITY_VALIDATED)).thenReturn(false)
+                }
+
+            val latest by collectLastValue(underTest.defaultConnectionIsValidated)
+
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun config_initiallyFromContext() =
+        testScope.runTest {
+            overrideResource(R.bool.config_showMin3G, true)
+            val configFromContext = MobileMappings.Config.readConfig(context)
+            assertThat(configFromContext.showAtLeast3G).isTrue()
+
+            // The initial value will be fetched when the repo is created, so we need to override
+            // the resources and then re-create the repo.
+            underTest =
+                MobileConnectionsRepositoryKairosImpl(
+                    connectivityRepository,
+                    subscriptionManager,
+                    subscriptionManagerProxy,
+                    telephonyManager,
+                    logger,
+                    summaryLogger,
+                    mobileMappings,
+                    fakeBroadcastDispatcher,
+                    context,
+                    testDispatcher,
+                    testScope.backgroundScope,
+                    testDispatcher,
+                    airplaneModeRepository,
+                    wifiRepository,
+                    fullConnectionFactory,
+                    updateMonitor,
+                    mock(),
+                )
+
+            val latest by collectLastValue(underTest.defaultDataSubRatConfig)
+
+            assertTrue(latest!!.areEqual(configFromContext))
+            assertTrue(latest!!.showAtLeast3G)
+        }
+
+    @Test
+    fun config_subIdChangeEvent_updated() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.defaultDataSubRatConfig)
+
+            assertThat(latest!!.showAtLeast3G).isFalse()
+
+            overrideResource(R.bool.config_showMin3G, true)
+            val configFromContext = MobileMappings.Config.readConfig(context)
+            assertThat(configFromContext.showAtLeast3G).isTrue()
+
+            // WHEN the change event is fired
+            val intent =
+                Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+                    .putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_1_ID)
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent)
+
+            // THEN the config is updated
+            assertTrue(latest!!.areEqual(configFromContext))
+            assertTrue(latest!!.showAtLeast3G)
+        }
+
+    @Test
+    fun config_carrierConfigChangeEvent_updated() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.defaultDataSubRatConfig)
+
+            assertThat(latest!!.showAtLeast3G).isFalse()
+
+            overrideResource(R.bool.config_showMin3G, true)
+            val configFromContext = MobileMappings.Config.readConfig(context)
+            assertThat(configFromContext.showAtLeast3G).isTrue()
+
+            // WHEN the change event is fired
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+                context,
+                Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED),
+            )
+
+            // THEN the config is updated
+            assertThat(latest!!.areEqual(configFromContext)).isTrue()
+            assertThat(latest!!.showAtLeast3G).isTrue()
+        }
+
+    @Test
+    fun carrierConfig_initialValueIsFetched() =
+        testScope.runTest {
+            // Value starts out false
+            assertThat(underTest.defaultDataSubRatConfig.value.showAtLeast3G).isFalse()
+
+            overrideResource(R.bool.config_showMin3G, true)
+            val configFromContext = MobileMappings.Config.readConfig(context)
+            assertThat(configFromContext.showAtLeast3G).isTrue()
+
+            // WHEN the change event is fired
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+                context,
+                Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED),
+            )
+
+            // WHEN collection starts AFTER the broadcast is sent out
+            val latest by collectLastValue(underTest.defaultDataSubRatConfig)
+
+            // THEN the config has the updated value
+            assertThat(latest!!.areEqual(configFromContext)).isTrue()
+            assertThat(latest!!.showAtLeast3G).isTrue()
+        }
+
+    @Test
+    fun activeDataChange_inSameGroup_emitsUnit() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.activeSubChangedInGroupEvent)
+
+            getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+                .onActiveDataSubscriptionIdChanged(SUB_3_ID_GROUPED)
+            getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+                .onActiveDataSubscriptionIdChanged(SUB_4_ID_GROUPED)
+
+            assertThat(latest).isEqualTo(Unit)
+        }
+
+    @Test
+    fun activeDataChange_notInSameGroup_doesNotEmit() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.activeSubChangedInGroupEvent)
+
+            getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+                .onActiveDataSubscriptionIdChanged(SUB_3_ID_GROUPED)
+            getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+                .onActiveDataSubscriptionIdChanged(SUB_1_ID)
+
+            assertThat(latest).isEqualTo(null)
+        }
+
+    @Test
+    fun anySimSecure_propagatesStateFromKeyguardUpdateMonitor() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.isAnySimSecure)
+            assertThat(latest).isFalse()
+
+            val updateMonitorCallback = argumentCaptor<KeyguardUpdateMonitorCallback>()
+            verify(updateMonitor).registerCallback(updateMonitorCallback.capture())
+
+            whenever(updateMonitor.isSimPinSecure).thenReturn(true)
+            updateMonitorCallback.value.onSimStateChanged(0, 0, 0)
+
+            assertThat(latest).isTrue()
+
+            whenever(updateMonitor.isSimPinSecure).thenReturn(false)
+            updateMonitorCallback.value.onSimStateChanged(0, 0, 0)
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun getIsAnySimSecure_delegatesCallToKeyguardUpdateMonitor() =
+        testScope.runTest {
+            assertThat(underTest.getIsAnySimSecure()).isFalse()
+
+            whenever(updateMonitor.isSimPinSecure).thenReturn(true)
+
+            assertThat(underTest.getIsAnySimSecure()).isTrue()
+        }
+
+    @Test
+    fun noSubscriptionsInEcmMode_notInEcmMode() =
+        testScope.runTest {
+            whenever(telephonyManager.emergencyCallbackMode).thenReturn(false)
+
+            runCurrent()
+
+            assertThat(underTest.isInEcmMode()).isFalse()
+        }
+
+    @Test
+    fun someSubscriptionsInEcmMode_inEcmMode() =
+        testScope.runTest {
+            whenever(telephonyManager.emergencyCallbackMode).thenReturn(true)
+
+            runCurrent()
+
+            assertThat(underTest.isInEcmMode()).isTrue()
+        }
+
+    private fun TestScope.getDefaultNetworkCallback(): ConnectivityManager.NetworkCallback {
+        runCurrent()
+        val callbackCaptor = argumentCaptor<ConnectivityManager.NetworkCallback>()
+        verify(connectivityManager).registerDefaultNetworkCallback(callbackCaptor.capture())
+        return callbackCaptor.value!!
+    }
+
+    private fun setWifiState(isCarrierMerged: Boolean) {
+        if (isCarrierMerged) {
+            val mergedEntry =
+                mock<MergedCarrierEntry>().apply {
+                    whenever(this.isPrimaryNetwork).thenReturn(true)
+                    whenever(this.isDefaultNetwork).thenReturn(true)
+                    whenever(this.subscriptionId).thenReturn(SUB_CM_ID)
+                }
+            whenever(wifiPickerTracker.mergedCarrierEntry).thenReturn(mergedEntry)
+            whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(null)
+        } else {
+            val wifiEntry =
+                mock<WifiEntry>().apply {
+                    whenever(this.isPrimaryNetwork).thenReturn(true)
+                    whenever(this.isDefaultNetwork).thenReturn(true)
+                }
+            whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
+            whenever(wifiPickerTracker.mergedCarrierEntry).thenReturn(null)
+        }
+        wifiPickerTrackerCallback.value.onWifiEntriesChanged()
+    }
+
+    private fun TestScope.getSubscriptionCallback():
+        SubscriptionManager.OnSubscriptionsChangedListener {
+        runCurrent()
+        val callbackCaptor = argumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener>()
+        verify(subscriptionManager)
+            .addOnSubscriptionsChangedListener(any(), callbackCaptor.capture())
+        return callbackCaptor.value!!
+    }
+
+    private fun TestScope.getTelephonyCallbacks(): List<TelephonyCallback> {
+        runCurrent()
+        val callbackCaptor = argumentCaptor<TelephonyCallback>()
+        verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
+        return callbackCaptor.allValues
+    }
+
+    private inline fun <reified T> TestScope.getTelephonyCallbackForType(): T {
+        val cbs = this.getTelephonyCallbacks().filterIsInstance<T>()
+        assertThat(cbs.size).isEqualTo(1)
+        return cbs[0]
+    }
+
+    companion object {
+        // Subscription 1
+        private const val SUB_1_ID = 1
+        private const val SUB_1_NAME = "Carrier $SUB_1_ID"
+        private val GROUP_1 = ParcelUuid(UUID.randomUUID())
+        private val SUB_1 =
+            mock<SubscriptionInfo>().also {
+                whenever(it.subscriptionId).thenReturn(SUB_1_ID)
+                whenever(it.groupUuid).thenReturn(GROUP_1)
+                whenever(it.carrierName).thenReturn(SUB_1_NAME)
+                whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
+            }
+        private val MODEL_1 =
+            SubscriptionModel(
+                subscriptionId = SUB_1_ID,
+                groupUuid = GROUP_1,
+                carrierName = SUB_1_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+
+        // Subscription 2
+        private const val SUB_2_ID = 2
+        private const val SUB_2_NAME = "Carrier $SUB_2_ID"
+        private val GROUP_2 = ParcelUuid(UUID.randomUUID())
+        private val SUB_2 =
+            mock<SubscriptionInfo>().also {
+                whenever(it.subscriptionId).thenReturn(SUB_2_ID)
+                whenever(it.groupUuid).thenReturn(GROUP_2)
+                whenever(it.carrierName).thenReturn(SUB_2_NAME)
+                whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
+            }
+        private val MODEL_2 =
+            SubscriptionModel(
+                subscriptionId = SUB_2_ID,
+                groupUuid = GROUP_2,
+                carrierName = SUB_2_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+
+        // Subs 3 and 4 are considered to be in the same group ------------------------------------
+        private val GROUP_ID_3_4 = ParcelUuid(UUID.randomUUID())
+
+        // Subscription 3
+        private const val SUB_3_ID_GROUPED = 3
+        private val SUB_3 =
+            mock<SubscriptionInfo>().also {
+                whenever(it.subscriptionId).thenReturn(SUB_3_ID_GROUPED)
+                whenever(it.groupUuid).thenReturn(GROUP_ID_3_4)
+                whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
+            }
+
+        // Subscription 4
+        private const val SUB_4_ID_GROUPED = 4
+        private val SUB_4 =
+            mock<SubscriptionInfo>().also {
+                whenever(it.subscriptionId).thenReturn(SUB_4_ID_GROUPED)
+                whenever(it.groupUuid).thenReturn(GROUP_ID_3_4)
+                whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
+            }
+
+        // Subs 3 and 4 are considered to be in the same group ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+        private const val NET_ID = 123
+        private val NETWORK = mock<Network>().apply { whenever(getNetId()).thenReturn(NET_ID) }
+
+        // Carrier merged subscription
+        private const val SUB_CM_ID = 5
+        private const val SUB_CM_NAME = "Carrier $SUB_CM_ID"
+        private val SUB_CM =
+            mock<SubscriptionInfo>().also {
+                whenever(it.subscriptionId).thenReturn(SUB_CM_ID)
+                whenever(it.carrierName).thenReturn(SUB_CM_NAME)
+                whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
+            }
+        private val MODEL_CM =
+            SubscriptionModel(
+                subscriptionId = SUB_CM_ID,
+                carrierName = SUB_CM_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+
+        private val WIFI_INFO_CM =
+            mock<WifiInfo>().apply {
+                whenever(this.isPrimary).thenReturn(true)
+                whenever(this.isCarrierMerged).thenReturn(true)
+                whenever(this.subscriptionId).thenReturn(SUB_CM_ID)
+            }
+        private val WIFI_NETWORK_CAPS_CM =
+            mock<NetworkCapabilities>().also {
+                whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+                whenever(it.transportInfo).thenReturn(WIFI_INFO_CM)
+                whenever(it.hasCapability(NET_CAPABILITY_VALIDATED)).thenReturn(true)
+            }
+
+        private val WIFI_INFO_ACTIVE =
+            mock<WifiInfo>().apply {
+                whenever(this.isPrimary).thenReturn(true)
+                whenever(this.isCarrierMerged).thenReturn(false)
+            }
+        private val WIFI_NETWORK_CAPS_ACTIVE =
+            mock<NetworkCapabilities>().also {
+                whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+                whenever(it.transportInfo).thenReturn(WIFI_INFO_ACTIVE)
+                whenever(it.hasCapability(NET_CAPABILITY_VALIDATED)).thenReturn(true)
+            }
+
+        /**
+         * To properly mimic telephony manager, create a service state, and then turn it into an
+         * intent
+         */
+        private fun serviceStateIntent(subId: Int): Intent {
+            return Intent(Intent.ACTION_SERVICE_STATE).apply {
+                putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId)
+            }
+        }
+    }
+}
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 c71162a..a18495e 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
@@ -18,6 +18,7 @@
 
 import android.net.wifi.WifiManager
 import com.android.systemui.CoreStartable
+import com.android.systemui.Flags
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.LogBufferFactory
@@ -36,6 +37,7 @@
 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.data.repository.MobileRepositorySwitcherKairos
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl
 import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter
@@ -74,6 +76,7 @@
 import dagger.multibindings.IntoMap
 import java.util.function.Supplier
 import javax.inject.Named
+import javax.inject.Provider
 import kotlinx.coroutines.flow.Flow
 
 @Module
@@ -117,11 +120,6 @@
 
     @Binds abstract fun wifiInteractor(impl: WifiInteractorImpl): WifiInteractor
 
-    @Binds
-    abstract fun mobileConnectionsRepository(
-        impl: MobileRepositorySwitcher
-    ): MobileConnectionsRepository
-
     @Binds abstract fun userSetupRepository(impl: UserSetupRepositoryImpl): UserSetupRepository
 
     @Binds abstract fun mobileMappingsProxy(impl: MobileMappingsProxyImpl): MobileMappingsProxy
@@ -158,6 +156,18 @@
     companion object {
 
         @Provides
+        fun mobileConnectionsRepository(
+            impl: Provider<MobileRepositorySwitcher>,
+            kairosImpl: Provider<MobileRepositorySwitcherKairos>,
+        ): MobileConnectionsRepository {
+            return if (Flags.statusBarMobileIconKairos()) {
+                kairosImpl.get()
+            } else {
+                impl.get()
+            }
+        }
+
+        @Provides
         @SysUISingleton
         fun provideRealWifiRepository(
             wifiManager: WifiManager?,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryKairos.kt
new file mode 100644
index 0000000..8e53f64
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryKairos.kt
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2022 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.telephony.CellSignalStrength
+import android.telephony.SubscriptionInfo
+import android.telephony.TelephonyManager
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import kotlinx.coroutines.flow.StateFlow
+
+/**
+ * Every mobile line of service can be identified via a [SubscriptionInfo] object. We set up a
+ * repository for each individual, tracked subscription via [MobileConnectionsRepository], and this
+ * repository is responsible for setting up a [TelephonyManager] object tied to its subscriptionId
+ *
+ * There should only ever be one [MobileConnectionRepositoryKairos] per subscription, since
+ * [TelephonyManager] limits the number of callbacks that can be registered per process.
+ *
+ * This repository should have all of the relevant information for a single line of service, which
+ * eventually becomes a single icon in the status bar.
+ */
+interface MobileConnectionRepositoryKairos {
+    /** The subscriptionId that this connection represents */
+    val subId: Int
+
+    /** The carrierId for this connection. See [TelephonyManager.getSimCarrierId] */
+    val carrierId: StateFlow<Int>
+
+    /** Reflects the value from the carrier config INFLATE_SIGNAL_STRENGTH for this connection */
+    val inflateSignalStrength: StateFlow<Boolean>
+
+    /** Carrier config KEY_SHOW_5G_SLICE_ICON_BOOL for this connection */
+    val allowNetworkSliceIndicator: StateFlow<Boolean>
+
+    /**
+     * The table log buffer created for this connection. Will have the name "MobileConnectionLog
+     * [subId]"
+     */
+    val tableLogBuffer: TableLogBuffer
+
+    /** True if the [android.telephony.ServiceState] says this connection is emergency calls only */
+    val isEmergencyOnly: StateFlow<Boolean>
+
+    /** True if [android.telephony.ServiceState] says we are roaming */
+    val isRoaming: StateFlow<Boolean>
+
+    /**
+     * See [android.telephony.ServiceState.getOperatorAlphaShort], this value is defined as the
+     * current registered operator name in short alphanumeric format. In some cases this name might
+     * be preferred over other methods of calculating the network name
+     */
+    val operatorAlphaShort: StateFlow<String?>
+
+    /**
+     * TODO (b/263167683): Clarify this field
+     *
+     * This check comes from [com.android.settingslib.Utils.isInService]. It is intended to be a
+     * mapping from a ServiceState to a notion of connectivity. Notably, it will consider a
+     * connection to be in-service if either the voice registration state is IN_SERVICE or the data
+     * registration state is IN_SERVICE and NOT IWLAN.
+     */
+    val isInService: StateFlow<Boolean>
+
+    /**
+     * True if this subscription is actively connected to a non-terrestrial network and false
+     * otherwise. Reflects [android.telephony.ServiceState.isUsingNonTerrestrialNetwork].
+     *
+     * Notably: This value reflects that this subscription is **currently** using a non-terrestrial
+     * network, because some subscriptions can switch between terrestrial and non-terrestrial
+     * networks. [SubscriptionModel.isExclusivelyNonTerrestrial] reflects whether a subscription is
+     * configured to exclusively connect to non-terrestrial networks. [isNonTerrestrial] can change
+     * during the lifetime of a subscription but [SubscriptionModel.isExclusivelyNonTerrestrial]
+     * will stay constant.
+     */
+    val isNonTerrestrial: StateFlow<Boolean>
+
+    /** True if [android.telephony.SignalStrength] told us that this connection is using GSM */
+    val isGsm: StateFlow<Boolean>
+
+    /**
+     * There is still specific logic in the pipeline that calls out CDMA level explicitly. This
+     * field is not completely orthogonal to [primaryLevel], because CDMA could be primary.
+     */
+    // @IntRange(from = 0, to = 4)
+    val cdmaLevel: StateFlow<Int>
+
+    /** [android.telephony.SignalStrength]'s concept of the overall signal level */
+    // @IntRange(from = 0, to = 4)
+    val primaryLevel: StateFlow<Int>
+
+    /**
+     * This level can be used to reflect the signal strength when in carrier roaming NTN mode
+     * (carrier-based satellite)
+     */
+    val satelliteLevel: StateFlow<Int>
+
+    /** The current data connection state. See [DataConnectionState] */
+    val dataConnectionState: StateFlow<DataConnectionState>
+
+    /** The current data activity direction. See [DataActivityModel] */
+    val dataActivityDirection: StateFlow<DataActivityModel>
+
+    /** True if there is currently a carrier network change in process */
+    val carrierNetworkChangeActive: StateFlow<Boolean>
+
+    /**
+     * [resolvedNetworkType] is the [TelephonyDisplayInfo.getOverrideNetworkType] if it exists or
+     * [TelephonyDisplayInfo.getNetworkType]. This is used to look up the proper network type icon
+     */
+    val resolvedNetworkType: StateFlow<ResolvedNetworkType>
+
+    /** The total number of levels. Used with [SignalDrawable]. */
+    val numberOfLevels: StateFlow<Int>
+
+    /** Observable tracking [TelephonyManager.isDataConnectionAllowed] */
+    val dataEnabled: StateFlow<Boolean>
+
+    /**
+     * See [TelephonyManager.getCdmaEnhancedRoamingIndicatorDisplayNumber]. This bit only matters if
+     * the connection type is CDMA.
+     *
+     * True if the Enhanced Roaming Indicator (ERI) display number is not [TelephonyManager.ERI_OFF]
+     */
+    val cdmaRoaming: StateFlow<Boolean>
+
+    /** The service provider name for this network connection, or the default name. */
+    val networkName: StateFlow<NetworkNameModel>
+
+    /**
+     * The service provider name for this network connection, or the default name.
+     *
+     * TODO(b/296600321): De-duplicate this field with [networkName] after determining the data
+     *   provided is identical
+     */
+    val carrierName: StateFlow<NetworkNameModel>
+
+    /**
+     * True if this type of connection is allowed while airplane mode is on, and false otherwise.
+     */
+    val isAllowedDuringAirplaneMode: StateFlow<Boolean>
+
+    /**
+     * True if this network has NET_CAPABILITIY_PRIORITIZE_LATENCY, and can be considered to be a
+     * network slice
+     */
+    val hasPrioritizedNetworkCapabilities: StateFlow<Boolean>
+
+    /**
+     * True if this connection is in emergency callback mode.
+     *
+     * @see [TelephonyManager.getEmergencyCallbackMode]
+     */
+    suspend fun isInEcmMode(): Boolean
+
+    companion object {
+        /** The default number of levels to use for [numberOfLevels]. */
+        val DEFAULT_NUM_LEVELS = CellSignalStrength.getNumSignalStrengthLevels()
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKairos.kt
new file mode 100644
index 0000000..b3cbbfd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKairos.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2022 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.telephony.CarrierConfigManager
+import android.telephony.SubscriptionManager
+import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.settingslib.mobile.MobileMappings
+import com.android.settingslib.mobile.MobileMappings.Config
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
+
+/**
+ * Repo for monitoring the complete active subscription info list, to be consumed and filtered based
+ * on various policy
+ */
+interface MobileConnectionsRepositoryKairos {
+    /** Observable list of current mobile subscriptions */
+    val subscriptions: StateFlow<List<SubscriptionModel>>
+
+    /**
+     * Observable for the subscriptionId of the current mobile data connection. Null if we don't
+     * have a valid subscription id
+     */
+    val activeMobileDataSubscriptionId: StateFlow<Int?>
+
+    /** Repo that tracks the current [activeMobileDataSubscriptionId] */
+    val activeMobileDataRepository: StateFlow<MobileConnectionRepository?>
+
+    /**
+     * Observable event for when the active data sim switches but the group stays the same. E.g.,
+     * CBRS switching would trigger this
+     */
+    val activeSubChangedInGroupEvent: Flow<Unit>
+
+    /** Tracks [SubscriptionManager.getDefaultDataSubscriptionId]. Null if there is no default */
+    val defaultDataSubId: StateFlow<Int?>
+
+    /**
+     * True if the default network connection is a mobile-like connection and false otherwise.
+     *
+     * This is typically shown by having [android.net.NetworkCapabilities.TRANSPORT_CELLULAR], but
+     * there are edge cases (like carrier merged wifi) that could also result in the default
+     * connection being mobile-like.
+     */
+    val mobileIsDefault: StateFlow<Boolean>
+
+    /**
+     * True if the device currently has a carrier merged connection.
+     *
+     * See [CarrierMergedConnectionRepository] for more info.
+     */
+    val hasCarrierMergedConnection: Flow<Boolean>
+
+    /** True if the default network connection is validated and false otherwise. */
+    val defaultConnectionIsValidated: StateFlow<Boolean>
+
+    /** Get or create a repository for the line of service for the given subscription ID */
+    fun getRepoForSubId(subId: Int): MobileConnectionRepository
+
+    /**
+     * [Config] is an object that tracks relevant configuration flags for a given subscription ID.
+     * In the case of [MobileMappings], it's hard-coded to check the default data subscription's
+     * config, so this will apply to every icon that we care about.
+     *
+     * Relevant bits in the config are things like
+     * [CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL]
+     *
+     * This flow will produce whenever the default data subscription or the carrier config changes.
+     */
+    val defaultDataSubRatConfig: StateFlow<Config>
+
+    /** The icon mapping from network type to [MobileIconGroup] for the default subscription */
+    val defaultMobileIconMapping: Flow<Map<String, MobileIconGroup>>
+
+    /** Fallback [MobileIconGroup] in the case where there is no icon in the mapping */
+    val defaultMobileIconGroup: Flow<MobileIconGroup>
+
+    /**
+     * Can the device make emergency calls using the device-based service state? This field is only
+     * useful when all known active subscriptions are OOS and not emergency call capable.
+     *
+     * Specifically, this checks every [ServiceState] of the device, and looks for any that report
+     * [ServiceState.isEmergencyOnly].
+     *
+     * This is an eager flow, and re-evaluates whenever ACTION_SERVICE_STATE is sent for subId = -1.
+     */
+    val isDeviceEmergencyCallCapable: StateFlow<Boolean>
+
+    /**
+     * If any active SIM on the device is in
+     * [android.telephony.TelephonyManager.SIM_STATE_PIN_REQUIRED] or
+     * [android.telephony.TelephonyManager.SIM_STATE_PUK_REQUIRED] or
+     * [android.telephony.TelephonyManager.SIM_STATE_PERM_DISABLED]
+     */
+    val isAnySimSecure: Flow<Boolean>
+
+    /**
+     * Returns whether any active SIM on the device is in
+     * [android.telephony.TelephonyManager.SIM_STATE_PIN_REQUIRED] or
+     * [android.telephony.TelephonyManager.SIM_STATE_PUK_REQUIRED] or
+     * [android.telephony.TelephonyManager.SIM_STATE_PERM_DISABLED].
+     *
+     * Note: Unfortunately, we cannot name this [isAnySimSecure] due to a conflict with the flow
+     * name above (Java code-gen is having issues with it).
+     */
+    fun getIsAnySimSecure(): Boolean
+
+    /**
+     * Checks if any subscription has [android.telephony.TelephonyManager.getEmergencyCallbackMode]
+     * == true
+     */
+    suspend fun isInEcmMode(): Boolean
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
index 66587c7..caf4bf5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
@@ -48,9 +48,9 @@
  * something like this:
  * ```
  * RealRepository
- *                 │
- *                 ├──►RepositorySwitcher──►RealInteractor──►RealViewModel
- *                 │
+ *       │
+ *       ├──►RepositorySwitcher──►RealInteractor──►RealViewModel
+ *       │
  * DemoRepository
  * ```
  *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherKairos.kt
new file mode 100644
index 0000000..3c855a9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherKairos.kt
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2022 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.Bundle
+import androidx.annotation.VisibleForTesting
+import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.MobileMappings
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.demomode.DemoMode
+import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * A provider for the [MobileConnectionsRepository] interface that can choose between the Demo and
+ * Prod concrete implementations at runtime. It works by defining a base flow, [activeRepo], which
+ * switches based on the latest information from [DemoModeController], and switches every flow in
+ * the interface to point to the currently-active provider. This allows us to put the demo mode
+ * interface in its own repository, completely separate from the real version, while still using all
+ * of the prod implementations for the rest of the pipeline (interactors and onward). Looks
+ * something like this:
+ * ```
+ * RealRepository
+ *       │
+ *       ├──►RepositorySwitcher──►RealInteractor──►RealViewModel
+ *       │
+ * DemoRepository
+ * ```
+ *
+ * NOTE: because the UI layer for mobile icons relies on a nested-repository structure, it is likely
+ * that we will have to drain the subscription list whenever demo mode changes. Otherwise if a real
+ * subscription list [1] is replaced with a demo subscription list [1], the view models will not see
+ * a change (due to `distinctUntilChanged`) and will not refresh their data providers to the demo
+ * implementation.
+ */
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@SysUISingleton
+class MobileRepositorySwitcherKairos
+@Inject
+constructor(
+    @Background scope: CoroutineScope,
+    val realRepository: MobileConnectionsRepositoryImpl,
+    val demoMobileConnectionsRepository: DemoMobileConnectionsRepository,
+    demoModeController: DemoModeController,
+) : MobileConnectionsRepository {
+
+    val isDemoMode: StateFlow<Boolean> =
+        conflatedCallbackFlow {
+                val callback =
+                    object : DemoMode {
+                        override fun dispatchDemoCommand(command: String?, args: Bundle?) {
+                            // Nothing, we just care about on/off
+                        }
+
+                        override fun onDemoModeStarted() {
+                            demoMobileConnectionsRepository.startProcessingCommands()
+                            trySend(true)
+                        }
+
+                        override fun onDemoModeFinished() {
+                            demoMobileConnectionsRepository.stopProcessingCommands()
+                            trySend(false)
+                        }
+                    }
+
+                demoModeController.addCallback(callback)
+                awaitClose { demoModeController.removeCallback(callback) }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), demoModeController.isInDemoMode)
+
+    // Convenient definition flow for the currently active repo (based on demo mode or not)
+    @VisibleForTesting
+    val activeRepo: StateFlow<MobileConnectionsRepository> =
+        isDemoMode
+            .mapLatest { demoMode ->
+                if (demoMode) {
+                    demoMobileConnectionsRepository
+                } else {
+                    realRepository
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), realRepository)
+
+    override val subscriptions: StateFlow<List<SubscriptionModel>> =
+        activeRepo
+            .flatMapLatest { it.subscriptions }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), realRepository.subscriptions.value)
+
+    override val activeMobileDataSubscriptionId: StateFlow<Int?> =
+        activeRepo
+            .flatMapLatest { it.activeMobileDataSubscriptionId }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                realRepository.activeMobileDataSubscriptionId.value,
+            )
+
+    override val activeMobileDataRepository: StateFlow<MobileConnectionRepository?> =
+        activeRepo
+            .flatMapLatest { it.activeMobileDataRepository }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                realRepository.activeMobileDataRepository.value,
+            )
+
+    override val activeSubChangedInGroupEvent: Flow<Unit> =
+        activeRepo.flatMapLatest { it.activeSubChangedInGroupEvent }
+
+    override val defaultDataSubRatConfig: StateFlow<MobileMappings.Config> =
+        activeRepo
+            .flatMapLatest { it.defaultDataSubRatConfig }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                realRepository.defaultDataSubRatConfig.value,
+            )
+
+    override val defaultMobileIconMapping: Flow<Map<String, SignalIcon.MobileIconGroup>> =
+        activeRepo.flatMapLatest { it.defaultMobileIconMapping }
+
+    override val defaultMobileIconGroup: Flow<SignalIcon.MobileIconGroup> =
+        activeRepo.flatMapLatest { it.defaultMobileIconGroup }
+
+    override val isDeviceEmergencyCallCapable: StateFlow<Boolean> =
+        activeRepo
+            .flatMapLatest { it.isDeviceEmergencyCallCapable }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                realRepository.isDeviceEmergencyCallCapable.value,
+            )
+
+    override val isAnySimSecure: Flow<Boolean> = activeRepo.flatMapLatest { it.isAnySimSecure }
+
+    override fun getIsAnySimSecure(): Boolean = activeRepo.value.getIsAnySimSecure()
+
+    override val defaultDataSubId: StateFlow<Int?> =
+        activeRepo
+            .flatMapLatest { it.defaultDataSubId }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), realRepository.defaultDataSubId.value)
+
+    override val mobileIsDefault: StateFlow<Boolean> =
+        activeRepo
+            .flatMapLatest { it.mobileIsDefault }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), realRepository.mobileIsDefault.value)
+
+    override val hasCarrierMergedConnection: StateFlow<Boolean> =
+        activeRepo
+            .flatMapLatest { it.hasCarrierMergedConnection }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                realRepository.hasCarrierMergedConnection.value,
+            )
+
+    override val defaultConnectionIsValidated: StateFlow<Boolean> =
+        activeRepo
+            .flatMapLatest { it.defaultConnectionIsValidated }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                realRepository.defaultConnectionIsValidated.value,
+            )
+
+    override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
+        if (isDemoMode.value) {
+            return demoMobileConnectionsRepository.getRepoForSubId(subId)
+        }
+        return realRepository.getRepoForSubId(subId)
+    }
+
+    override suspend fun isInEcmMode(): Boolean =
+        if (isDemoMode.value) {
+            demoMobileConnectionsRepository.isInEcmMode()
+        } else {
+            realRepository.isInEcmMode()
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepositoryKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepositoryKairos.kt
new file mode 100644
index 0000000..712ebdc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepositoryKairos.kt
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2023 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.demo
+
+import android.telephony.CellSignalStrength
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.TelephonyManager
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_CARRIER_ID
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_CARRIER_NETWORK_CHANGE
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_CDMA_LEVEL
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_EMERGENCY
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_IS_GSM
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_IS_IN_SERVICE
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_IS_NTN
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_OPERATOR
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_PRIMARY_LEVEL
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_ROAMING
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_SATELLITE_LEVEL
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * Demo version of [MobileConnectionRepository]. Note that this class shares all of its flows using
+ * [SharingStarted.WhileSubscribed()] to give the same semantics as using a regular
+ * [MutableStateFlow] while still logging all of the inputs in the same manor as the production
+ * repos.
+ */
+class DemoMobileConnectionRepositoryKairos(
+    override val subId: Int,
+    override val tableLogBuffer: TableLogBuffer,
+    val scope: CoroutineScope,
+) : MobileConnectionRepository, MobileConnectionRepositoryKairos {
+    private val _carrierId = MutableStateFlow(INVALID_SUBSCRIPTION_ID)
+    override val carrierId =
+        _carrierId
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_CARRIER_ID,
+                initialValue = _carrierId.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _carrierId.value)
+
+    private val _inflateSignalStrength: MutableStateFlow<Boolean> = MutableStateFlow(false)
+    override val inflateSignalStrength =
+        _inflateSignalStrength
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = "inflate",
+                initialValue = _inflateSignalStrength.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _inflateSignalStrength.value)
+
+    // I don't see a reason why we would turn the config off for demo mode.
+    override val allowNetworkSliceIndicator = MutableStateFlow(true)
+
+    private val _isEmergencyOnly = MutableStateFlow(false)
+    override val isEmergencyOnly =
+        _isEmergencyOnly
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_EMERGENCY,
+                initialValue = _isEmergencyOnly.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _isEmergencyOnly.value)
+
+    private val _isRoaming = MutableStateFlow(false)
+    override val isRoaming =
+        _isRoaming
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_ROAMING,
+                initialValue = _isRoaming.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _isRoaming.value)
+
+    private val _operatorAlphaShort: MutableStateFlow<String?> = MutableStateFlow(null)
+    override val operatorAlphaShort =
+        _operatorAlphaShort
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_OPERATOR,
+                initialValue = _operatorAlphaShort.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _operatorAlphaShort.value)
+
+    private val _isInService = MutableStateFlow(false)
+    override val isInService =
+        _isInService
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_IS_IN_SERVICE,
+                initialValue = _isInService.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _isInService.value)
+
+    private val _isNonTerrestrial = MutableStateFlow(false)
+    override val isNonTerrestrial =
+        _isNonTerrestrial
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_IS_NTN,
+                initialValue = _isNonTerrestrial.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _isNonTerrestrial.value)
+
+    private val _isGsm = MutableStateFlow(false)
+    override val isGsm =
+        _isGsm
+            .logDiffsForTable(tableLogBuffer, columnName = COL_IS_GSM, initialValue = _isGsm.value)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _isGsm.value)
+
+    private val _cdmaLevel = MutableStateFlow(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+    override val cdmaLevel =
+        _cdmaLevel
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_CDMA_LEVEL,
+                initialValue = _cdmaLevel.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _cdmaLevel.value)
+
+    private val _primaryLevel = MutableStateFlow(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+    override val primaryLevel =
+        _primaryLevel
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_PRIMARY_LEVEL,
+                initialValue = _primaryLevel.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _primaryLevel.value)
+
+    private val _satelliteLevel = MutableStateFlow(0)
+    override val satelliteLevel: StateFlow<Int> =
+        _satelliteLevel
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_SATELLITE_LEVEL,
+                initialValue = _satelliteLevel.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _satelliteLevel.value)
+
+    private val _dataConnectionState = MutableStateFlow(DataConnectionState.Disconnected)
+    override val dataConnectionState =
+        _dataConnectionState
+            .logDiffsForTable(tableLogBuffer, initialValue = _dataConnectionState.value)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _dataConnectionState.value)
+
+    private val _dataActivityDirection =
+        MutableStateFlow(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
+    override val dataActivityDirection =
+        _dataActivityDirection
+            .logDiffsForTable(tableLogBuffer, initialValue = _dataActivityDirection.value)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _dataActivityDirection.value)
+
+    private val _carrierNetworkChangeActive = MutableStateFlow(false)
+    override val carrierNetworkChangeActive =
+        _carrierNetworkChangeActive
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_CARRIER_NETWORK_CHANGE,
+                initialValue = _carrierNetworkChangeActive.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _carrierNetworkChangeActive.value)
+
+    private val _resolvedNetworkType: MutableStateFlow<ResolvedNetworkType> =
+        MutableStateFlow(ResolvedNetworkType.UnknownNetworkType)
+    override val resolvedNetworkType =
+        _resolvedNetworkType
+            .logDiffsForTable(tableLogBuffer, initialValue = _resolvedNetworkType.value)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _resolvedNetworkType.value)
+
+    override val numberOfLevels =
+        _inflateSignalStrength
+            .map { shouldInflate ->
+                if (shouldInflate) {
+                    DEFAULT_NUM_LEVELS + 1
+                } else {
+                    DEFAULT_NUM_LEVELS
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_NUM_LEVELS)
+
+    override val dataEnabled = MutableStateFlow(true)
+
+    override val cdmaRoaming = MutableStateFlow(false)
+
+    override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived(DEMO_CARRIER_NAME))
+
+    override val carrierName =
+        MutableStateFlow(NetworkNameModel.SubscriptionDerived(DEMO_CARRIER_NAME))
+
+    override val isAllowedDuringAirplaneMode = MutableStateFlow(false)
+
+    override val hasPrioritizedNetworkCapabilities = MutableStateFlow(false)
+
+    override suspend fun isInEcmMode(): Boolean = false
+
+    /**
+     * Process a new demo mobile event. Note that [resolvedNetworkType] must be passed in separately
+     * from the event, due to the requirement to reverse the mobile mappings lookup in the top-level
+     * repository.
+     */
+    fun processDemoMobileEvent(
+        event: FakeNetworkEventModel.Mobile,
+        resolvedNetworkType: ResolvedNetworkType,
+    ) {
+        // This is always true here, because we split out disabled states at the data-source level
+        dataEnabled.value = true
+        networkName.value = NetworkNameModel.IntentDerived(event.name)
+        carrierName.value = NetworkNameModel.SubscriptionDerived("${event.name} ${event.subId}")
+
+        _carrierId.value = event.carrierId ?: INVALID_SUBSCRIPTION_ID
+
+        _inflateSignalStrength.value = event.inflateStrength
+
+        cdmaRoaming.value = event.roaming
+        _isRoaming.value = event.roaming
+        // TODO(b/261029387): not yet supported
+        _isEmergencyOnly.value = false
+        _operatorAlphaShort.value = event.name
+        _isInService.value = (event.level ?: 0) > 0
+        // TODO(b/261029387): not yet supported
+        _isGsm.value = false
+        _cdmaLevel.value = event.level ?: 0
+        _primaryLevel.value = event.level ?: 0
+        // TODO(b/261029387): not yet supported
+        _dataConnectionState.value = DataConnectionState.Connected
+        _dataActivityDirection.value =
+            (event.activity ?: TelephonyManager.DATA_ACTIVITY_NONE).toMobileDataActivityModel()
+        _carrierNetworkChangeActive.value = event.carrierNetworkChange
+        _resolvedNetworkType.value = resolvedNetworkType
+        _isNonTerrestrial.value = event.ntn
+
+        isAllowedDuringAirplaneMode.value = false
+        hasPrioritizedNetworkCapabilities.value = event.slice
+    }
+
+    fun processCarrierMergedEvent(event: FakeWifiEventModel.CarrierMerged) {
+        // This is always true here, because we split out disabled states at the data-source level
+        dataEnabled.value = true
+        networkName.value = NetworkNameModel.IntentDerived(CARRIER_MERGED_NAME)
+        carrierName.value = NetworkNameModel.SubscriptionDerived(CARRIER_MERGED_NAME)
+        // TODO(b/276943904): is carrierId a thing with carrier merged networks?
+        _carrierId.value = INVALID_SUBSCRIPTION_ID
+        cdmaRoaming.value = false
+        _primaryLevel.value = event.level
+        _cdmaLevel.value = event.level
+        _dataActivityDirection.value = event.activity.toMobileDataActivityModel()
+
+        // These fields are always the same for carrier-merged networks
+        _resolvedNetworkType.value = ResolvedNetworkType.CarrierMergedNetworkType
+        _dataConnectionState.value = DataConnectionState.Connected
+        _isRoaming.value = false
+        _isEmergencyOnly.value = false
+        _operatorAlphaShort.value = null
+        _isInService.value = true
+        _isGsm.value = false
+        _carrierNetworkChangeActive.value = false
+        isAllowedDuringAirplaneMode.value = true
+        hasPrioritizedNetworkCapabilities.value = false
+    }
+
+    companion object {
+        private const val DEMO_CARRIER_NAME = "Demo Carrier"
+        private const val CARRIER_MERGED_NAME = "Carrier Merged Network"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryKairos.kt
new file mode 100644
index 0000000..dee59bd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryKairos.kt
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2022 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.demo
+
+import android.content.Context
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
+import android.util.Log
+import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.MobileMappings
+import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.log.table.TableLogBufferFactory
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.Mobile
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.MOBILE_CONNECTION_BUFFER_SIZE
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
+
+/** This repository vends out data based on demo mode commands */
+class DemoMobileConnectionsRepositoryKairos
+@Inject
+constructor(
+    private val mobileDataSource: DemoModeMobileConnectionDataSource,
+    private val wifiDataSource: DemoModeWifiDataSource,
+    @Background private val scope: CoroutineScope,
+    context: Context,
+    private val logFactory: TableLogBufferFactory,
+) : MobileConnectionsRepository, MobileConnectionsRepositoryKairos {
+
+    private var mobileDemoCommandJob: Job? = null
+    private var wifiDemoCommandJob: Job? = null
+
+    private var carrierMergedSubId: Int? = null
+
+    private var connectionRepoCache = mutableMapOf<Int, CacheContainer>()
+    private val subscriptionInfoCache = mutableMapOf<Int, SubscriptionModel>()
+    val demoModeFinishedEvent = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
+
+    private val _subscriptions = MutableStateFlow<List<SubscriptionModel>>(listOf())
+    override val subscriptions =
+        _subscriptions
+            .onEach { infos -> dropUnusedReposFromCache(infos) }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), _subscriptions.value)
+
+    private fun dropUnusedReposFromCache(newInfos: List<SubscriptionModel>) {
+        // Remove any connection repository from the cache that isn't in the new set of IDs. They
+        // will get garbage collected once their subscribers go away
+        val currentValidSubscriptionIds = newInfos.map { it.subscriptionId }
+
+        connectionRepoCache =
+            connectionRepoCache
+                .filter { currentValidSubscriptionIds.contains(it.key) }
+                .toMutableMap()
+    }
+
+    private fun maybeCreateSubscription(subId: Int) {
+        if (!subscriptionInfoCache.containsKey(subId)) {
+            SubscriptionModel(
+                    subscriptionId = subId,
+                    isOpportunistic = false,
+                    carrierName = DEFAULT_CARRIER_NAME,
+                    profileClass = PROFILE_CLASS_UNSET,
+                )
+                .also { subscriptionInfoCache[subId] = it }
+
+            _subscriptions.value = subscriptionInfoCache.values.toList()
+        }
+    }
+
+    // TODO(b/261029387): add a command for this value
+    override val activeMobileDataSubscriptionId =
+        subscriptions
+            .mapLatest { infos ->
+                // For now, active is just the first in the list
+                infos.firstOrNull()?.subscriptionId ?: INVALID_SUBSCRIPTION_ID
+            }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                subscriptions.value.firstOrNull()?.subscriptionId ?: INVALID_SUBSCRIPTION_ID,
+            )
+
+    override val activeMobileDataRepository: StateFlow<MobileConnectionRepository?> =
+        activeMobileDataSubscriptionId
+            .map { getRepoForSubId(it) }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                getRepoForSubId(activeMobileDataSubscriptionId.value),
+            )
+
+    // TODO(b/261029387): consider adding a demo command for this
+    override val activeSubChangedInGroupEvent: Flow<Unit> = flowOf()
+
+    /** Demo mode doesn't currently support modifications to the mobile mappings */
+    override val defaultDataSubRatConfig =
+        MutableStateFlow(MobileMappings.Config.readConfig(context))
+
+    override val defaultMobileIconGroup = flowOf(TelephonyIcons.THREE_G)
+
+    // TODO(b/339023069): demo command for device-based emergency calls state
+    override val isDeviceEmergencyCallCapable: StateFlow<Boolean> = MutableStateFlow(false)
+
+    override val isAnySimSecure: Flow<Boolean> = flowOf(getIsAnySimSecure())
+
+    override fun getIsAnySimSecure(): Boolean = false
+
+    override val defaultMobileIconMapping = MutableStateFlow(TelephonyIcons.ICON_NAME_TO_ICON)
+
+    /**
+     * In order to maintain compatibility with the old demo mode shell command API, reverse the
+     * [MobileMappings] lookup from (NetworkType: String -> Icon: MobileIconGroup), so that we can
+     * parse the string from the command line into a preferred icon group, and send _a_ valid
+     * network type for that icon through the pipeline.
+     *
+     * Note: collisions don't matter here, because the data source (the command line) only cares
+     * about the resulting icon, not the underlying network type.
+     */
+    private val mobileMappingsReverseLookup: StateFlow<Map<SignalIcon.MobileIconGroup, String>> =
+        defaultMobileIconMapping
+            .mapLatest { networkToIconMap -> networkToIconMap.reverse() }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                defaultMobileIconMapping.value.reverse(),
+            )
+
+    private fun <K, V> Map<K, V>.reverse() = entries.associateBy({ it.value }) { it.key }
+
+    // TODO(b/261029387): add a command for this value
+    override val defaultDataSubId: MutableStateFlow<Int?> = MutableStateFlow(null)
+
+    // TODO(b/261029387): not yet supported
+    override val mobileIsDefault: StateFlow<Boolean> = MutableStateFlow(true)
+
+    // TODO(b/261029387): not yet supported
+    override val hasCarrierMergedConnection = MutableStateFlow(false)
+
+    // TODO(b/261029387): not yet supported
+    override val defaultConnectionIsValidated: StateFlow<Boolean> = MutableStateFlow(true)
+
+    override fun getRepoForSubId(subId: Int): DemoMobileConnectionRepository {
+        val current = connectionRepoCache[subId]?.repo
+        if (current != null) {
+            return current
+        }
+
+        val new = createDemoMobileConnectionRepo(subId)
+        connectionRepoCache[subId] = new
+        return new.repo
+    }
+
+    private fun createDemoMobileConnectionRepo(subId: Int): CacheContainer {
+        val tableLogBuffer =
+            logFactory.getOrCreate("DemoMobileConnectionLog[$subId]", MOBILE_CONNECTION_BUFFER_SIZE)
+
+        val repo = DemoMobileConnectionRepository(subId, tableLogBuffer, scope)
+        return CacheContainer(repo, lastMobileState = null)
+    }
+
+    fun startProcessingCommands() {
+        mobileDemoCommandJob =
+            scope.launch {
+                mobileDataSource.mobileEvents.filterNotNull().collect { event ->
+                    processMobileEvent(event)
+                }
+            }
+        wifiDemoCommandJob =
+            scope.launch {
+                wifiDataSource.wifiEvents.filterNotNull().collect { event ->
+                    processWifiEvent(event)
+                }
+            }
+    }
+
+    fun stopProcessingCommands() {
+        mobileDemoCommandJob?.cancel()
+        wifiDemoCommandJob?.cancel()
+        _subscriptions.value = listOf()
+        connectionRepoCache.clear()
+        subscriptionInfoCache.clear()
+    }
+
+    override suspend fun isInEcmMode(): Boolean = false
+
+    private fun processMobileEvent(event: FakeNetworkEventModel) {
+        when (event) {
+            is Mobile -> {
+                processEnabledMobileState(event)
+            }
+            is MobileDisabled -> {
+                maybeRemoveSubscription(event.subId)
+            }
+        }
+    }
+
+    private fun processWifiEvent(event: FakeWifiEventModel) {
+        when (event) {
+            is FakeWifiEventModel.WifiDisabled -> disableCarrierMerged()
+            is FakeWifiEventModel.Wifi -> disableCarrierMerged()
+            is FakeWifiEventModel.CarrierMerged -> processCarrierMergedWifiState(event)
+        }
+    }
+
+    private fun processEnabledMobileState(event: Mobile) {
+        // get or create the connection repo, and set its values
+        val subId = event.subId ?: DEFAULT_SUB_ID
+        maybeCreateSubscription(subId)
+
+        val connection = getRepoForSubId(subId)
+        connectionRepoCache[subId]?.lastMobileState = event
+
+        // TODO(b/261029387): until we have a command, use the most recent subId
+        defaultDataSubId.value = subId
+
+        connection.processDemoMobileEvent(event, event.dataType.toResolvedNetworkType())
+    }
+
+    private fun processCarrierMergedWifiState(event: FakeWifiEventModel.CarrierMerged) {
+        // The new carrier merged connection is for a different sub ID, so disable carrier merged
+        // for the current (now old) sub
+        if (carrierMergedSubId != event.subscriptionId) {
+            disableCarrierMerged()
+        }
+
+        // get or create the connection repo, and set its values
+        val subId = event.subscriptionId
+        maybeCreateSubscription(subId)
+        carrierMergedSubId = subId
+
+        // TODO(b/261029387): until we have a command, use the most recent subId
+        defaultDataSubId.value = subId
+
+        val connection = getRepoForSubId(subId)
+        connection.processCarrierMergedEvent(event)
+    }
+
+    private fun maybeRemoveSubscription(subId: Int?) {
+        if (_subscriptions.value.isEmpty()) {
+            // Nothing to do here
+            return
+        }
+
+        val finalSubId =
+            subId
+                ?: run {
+                    // For sake of usability, we can allow for no subId arg if there is only one
+                    // subscription
+                    if (_subscriptions.value.size > 1) {
+                        Log.d(
+                            TAG,
+                            "processDisabledMobileState: Unable to infer subscription to " +
+                                "disable. Specify subId using '-e slot <subId>'" +
+                                "Known subIds: [${subIdsString()}]",
+                        )
+                        return
+                    }
+
+                    // Use the only existing subscription as our arg, since there is only one
+                    _subscriptions.value[0].subscriptionId
+                }
+
+        removeSubscription(finalSubId)
+    }
+
+    private fun disableCarrierMerged() {
+        val currentCarrierMergedSubId = carrierMergedSubId ?: return
+
+        // If this sub ID was previously not carrier merged, we should reset it to its previous
+        // connection.
+        val lastMobileState = connectionRepoCache[carrierMergedSubId]?.lastMobileState
+        if (lastMobileState != null) {
+            processEnabledMobileState(lastMobileState)
+        } else {
+            // Otherwise, just remove the subscription entirely
+            removeSubscription(currentCarrierMergedSubId)
+        }
+    }
+
+    private fun removeSubscription(subId: Int) {
+        val currentSubscriptions = _subscriptions.value
+        subscriptionInfoCache.remove(subId)
+        _subscriptions.value = currentSubscriptions.filter { it.subscriptionId != subId }
+    }
+
+    private fun subIdsString(): String =
+        _subscriptions.value.joinToString(",") { it.subscriptionId.toString() }
+
+    private fun SignalIcon.MobileIconGroup?.toResolvedNetworkType(): ResolvedNetworkType {
+        val key = mobileMappingsReverseLookup.value[this] ?: "dis"
+        return DefaultNetworkType(key)
+    }
+
+    companion object {
+        private const val TAG = "DemoMobileConnectionsRepo"
+
+        private const val DEFAULT_SUB_ID = 1
+        private const val DEFAULT_CARRIER_NAME = "demo carrier"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoModeMobileConnectionDataSourceKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoModeMobileConnectionDataSourceKairos.kt
new file mode 100644
index 0000000..b379384
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoModeMobileConnectionDataSourceKairos.kt
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2025 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.demo
+
+import android.os.Bundle
+import android.telephony.Annotation.DataActivityType
+import android.telephony.TelephonyManager.DATA_ACTIVITY_IN
+import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
+import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
+import android.telephony.TelephonyManager.DATA_ACTIVITY_OUT
+import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.demomode.DemoMode.COMMAND_NETWORK
+import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.Mobile
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.shareIn
+
+/**
+ * Data source that can map from demo mode commands to inputs into the
+ * [DemoMobileConnectionsRepository]'s flows
+ */
+@SysUISingleton
+class DemoModeMobileConnectionDataSourceKairos
+@Inject
+constructor(demoModeController: DemoModeController, @Background scope: CoroutineScope) {
+    private val demoCommandStream = demoModeController.demoFlowForCommand(COMMAND_NETWORK)
+
+    // If the args contains "mobile", then all of the args are relevant. It's just the way demo mode
+    // commands work and it's a little silly
+    private val _mobileCommands = demoCommandStream.map { args -> args.toMobileEvent() }
+    val mobileEvents = _mobileCommands.shareIn(scope, SharingStarted.WhileSubscribed())
+
+    private fun Bundle.toMobileEvent(): FakeNetworkEventModel? {
+        val mobile = getString("mobile") ?: return null
+        return if (mobile == "show") {
+            activeMobileEvent()
+        } else {
+            MobileDisabled(subId = getString("slot")?.toInt())
+        }
+    }
+
+    /** Parse a valid mobile command string into a network event */
+    private fun Bundle.activeMobileEvent(): Mobile {
+        // There are many key/value pairs supported by mobile demo mode. Bear with me here
+        val level = getString("level")?.toInt()
+        val dataType = getString("datatype")?.toDataType()
+        val slot = getString("slot")?.toInt()
+        val carrierId = getString("carrierid")?.toInt()
+        val inflateStrength = getString("inflate").toBoolean()
+        val activity = getString("activity")?.toActivity()
+        val carrierNetworkChange = getString("carriernetworkchange") == "show"
+        val roaming = getString("roam") == "show"
+        val name = getString("networkname") ?: "demo mode"
+        val slice = getString("slice").toBoolean()
+        val ntn = getString("ntn").toBoolean()
+
+        return Mobile(
+            level = level,
+            dataType = dataType,
+            subId = slot,
+            carrierId = carrierId,
+            inflateStrength = inflateStrength,
+            activity = activity,
+            carrierNetworkChange = carrierNetworkChange,
+            roaming = roaming,
+            name = name,
+            slice = slice,
+            ntn = ntn,
+        )
+    }
+}
+
+private fun String.toDataType(): MobileIconGroup =
+    when (this) {
+        "1x" -> TelephonyIcons.ONE_X
+        "3g" -> TelephonyIcons.THREE_G
+        "4g" -> TelephonyIcons.FOUR_G
+        "4g+" -> TelephonyIcons.FOUR_G_PLUS
+        "5g" -> TelephonyIcons.NR_5G
+        "5ge" -> TelephonyIcons.LTE_CA_5G_E
+        "5g+" -> TelephonyIcons.NR_5G_PLUS
+        "e" -> TelephonyIcons.E
+        "g" -> TelephonyIcons.G
+        "h" -> TelephonyIcons.H
+        "h+" -> TelephonyIcons.H_PLUS
+        "lte" -> TelephonyIcons.LTE
+        "lte+" -> TelephonyIcons.LTE_PLUS
+        "dis" -> TelephonyIcons.DATA_DISABLED
+        "not" -> TelephonyIcons.NOT_DEFAULT_DATA
+        else -> TelephonyIcons.UNKNOWN
+    }
+
+@DataActivityType
+private fun String.toActivity(): Int =
+    when (this) {
+        "inout" -> DATA_ACTIVITY_INOUT
+        "in" -> DATA_ACTIVITY_IN
+        "out" -> DATA_ACTIVITY_OUT
+        else -> DATA_ACTIVITY_NONE
+    }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryKairos.kt
new file mode 100644
index 0000000..4d80efc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryKairos.kt
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2025 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.prod
+
+import android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.TelephonyManager
+import android.util.Log
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepositoryKairos.Companion.DEFAULT_NUM_LEVELS
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
+
+/**
+ * A repository implementation for a carrier merged (aka VCN) network. A carrier merged network is
+ * delivered to SysUI as a wifi network (see [WifiNetworkModel.CarrierMerged], but is visually
+ * displayed as a mobile network triangle.
+ *
+ * See [android.net.wifi.WifiInfo.isCarrierMerged] for more information.
+ *
+ * See [MobileConnectionRepositoryImpl] for a repository implementation of a typical mobile
+ * connection.
+ */
+class CarrierMergedConnectionRepositoryKairos(
+    override val subId: Int,
+    override val tableLogBuffer: TableLogBuffer,
+    private val telephonyManager: TelephonyManager,
+    private val bgContext: CoroutineContext,
+    @Background private val scope: CoroutineScope,
+    val wifiRepository: WifiRepository,
+) : MobileConnectionRepository, MobileConnectionRepositoryKairos {
+    init {
+        if (telephonyManager.subscriptionId != subId) {
+            throw IllegalStateException(
+                "CarrierMergedRepo: TelephonyManager should be created with subId($subId). " +
+                    "Found ${telephonyManager.subscriptionId} instead."
+            )
+        }
+    }
+
+    /**
+     * Outputs the carrier merged network to use, or null if we don't have a valid carrier merged
+     * network.
+     */
+    private val network: Flow<WifiNetworkModel.CarrierMerged?> =
+        combine(
+            wifiRepository.isWifiEnabled,
+            wifiRepository.isWifiDefault,
+            wifiRepository.wifiNetwork,
+        ) { isEnabled, isDefault, network ->
+            when {
+                !isEnabled -> null
+                !isDefault -> null
+                network !is WifiNetworkModel.CarrierMerged -> null
+                network.subscriptionId != subId -> {
+                    Log.w(
+                        TAG,
+                        "Connection repo subId=$subId " +
+                            "does not equal wifi repo subId=${network.subscriptionId}; " +
+                            "not showing carrier merged",
+                    )
+                    null
+                }
+                else -> network
+            }
+        }
+
+    override val cdmaRoaming: StateFlow<Boolean> = MutableStateFlow(ROAMING).asStateFlow()
+
+    override val networkName: StateFlow<NetworkNameModel> =
+        network
+            // The SIM operator name should be the same throughout the lifetime of a subId, **but**
+            // it may not be available when this repo is created because it takes time to load. To
+            // be safe, we re-fetch it each time the network has changed.
+            .map { NetworkNameModel.SimDerived(telephonyManager.simOperatorName) }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                NetworkNameModel.SimDerived(telephonyManager.simOperatorName),
+            )
+
+    override val carrierName: StateFlow<NetworkNameModel> = networkName
+
+    override val numberOfLevels: StateFlow<Int> =
+        wifiRepository.wifiNetwork
+            .map {
+                if (it is WifiNetworkModel.CarrierMerged) {
+                    it.numberOfLevels
+                } else {
+                    DEFAULT_NUM_LEVELS
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_NUM_LEVELS)
+
+    override val primaryLevel =
+        network
+            .map { it?.level ?: SIGNAL_STRENGTH_NONE_OR_UNKNOWN }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+
+    override val cdmaLevel =
+        network
+            .map { it?.level ?: SIGNAL_STRENGTH_NONE_OR_UNKNOWN }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+
+    override val dataActivityDirection = wifiRepository.wifiActivity
+
+    override val resolvedNetworkType =
+        network
+            .map {
+                if (it != null) {
+                    ResolvedNetworkType.CarrierMergedNetworkType
+                } else {
+                    ResolvedNetworkType.UnknownNetworkType
+                }
+            }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                ResolvedNetworkType.UnknownNetworkType,
+            )
+
+    override val dataConnectionState =
+        network
+            .map {
+                if (it != null) {
+                    DataConnectionState.Connected
+                } else {
+                    DataConnectionState.Disconnected
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), DataConnectionState.Disconnected)
+
+    override val isRoaming = MutableStateFlow(false).asStateFlow()
+    override val carrierId = MutableStateFlow(INVALID_SUBSCRIPTION_ID).asStateFlow()
+    override val inflateSignalStrength = MutableStateFlow(false).asStateFlow()
+    override val allowNetworkSliceIndicator = MutableStateFlow(false).asStateFlow()
+    override val isEmergencyOnly = MutableStateFlow(false).asStateFlow()
+    override val operatorAlphaShort = MutableStateFlow(null).asStateFlow()
+    override val isInService = MutableStateFlow(true).asStateFlow()
+    override val isNonTerrestrial = MutableStateFlow(false).asStateFlow()
+    override val isGsm = MutableStateFlow(false).asStateFlow()
+    override val carrierNetworkChangeActive = MutableStateFlow(false).asStateFlow()
+    override val satelliteLevel = MutableStateFlow(0)
+
+    /**
+     * Carrier merged connections happen over wifi but are displayed as a mobile triangle. Because
+     * they occur over wifi, it's possible to have a valid carrier merged connection even during
+     * airplane mode. See b/291993542.
+     */
+    override val isAllowedDuringAirplaneMode = MutableStateFlow(true).asStateFlow()
+
+    /**
+     * It's not currently considered possible that a carrier merged network can have these
+     * prioritized capabilities. If we need to track them, we can add the same check as is in
+     * [MobileConnectionRepositoryImpl].
+     */
+    override val hasPrioritizedNetworkCapabilities = MutableStateFlow(false).asStateFlow()
+
+    override val dataEnabled: StateFlow<Boolean> = wifiRepository.isWifiEnabled
+
+    override suspend fun isInEcmMode(): Boolean =
+        withContext(bgContext) { telephonyManager.emergencyCallbackMode }
+
+    companion object {
+        // Carrier merged is never roaming
+        private const val ROAMING = false
+    }
+
+    @SysUISingleton
+    class Factory
+    @Inject
+    constructor(
+        private val telephonyManager: TelephonyManager,
+        @Background private val bgContext: CoroutineContext,
+        @Background private val scope: CoroutineScope,
+        private val wifiRepository: WifiRepository,
+    ) {
+        fun build(subId: Int, mobileLogger: TableLogBuffer): MobileConnectionRepository {
+            return CarrierMergedConnectionRepository(
+                subId,
+                mobileLogger,
+                telephonyManager.createForSubscriptionId(subId),
+                bgContext,
+                scope,
+                wifiRepository,
+            )
+        }
+    }
+}
+
+private const val TAG = "CarrierMergedConnectionRepository"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryKairos.kt
new file mode 100644
index 0000000..38e6216
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryKairos.kt
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2022 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.prod
+
+import android.util.IndentingPrintWriter
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.TableLogBufferFactory
+import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepositoryKairos
+import java.io.PrintWriter
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * A repository that fully implements a mobile connection.
+ *
+ * This connection could either be a typical mobile connection (see [MobileConnectionRepositoryImpl]
+ * or a carrier merged connection (see [CarrierMergedConnectionRepository]). This repository
+ * switches between the two types of connections based on whether the connection is currently
+ * carrier merged (see [setIsCarrierMerged]).
+ */
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+class FullMobileConnectionRepositoryKairos(
+    override val subId: Int,
+    startingIsCarrierMerged: Boolean,
+    override val tableLogBuffer: TableLogBuffer,
+    subscriptionModel: Flow<SubscriptionModel?>,
+    private val defaultNetworkName: NetworkNameModel,
+    private val networkNameSeparator: String,
+    @Background scope: CoroutineScope,
+    private val mobileRepoFactory: MobileConnectionRepositoryImpl.Factory,
+    private val carrierMergedRepoFactory: CarrierMergedConnectionRepository.Factory,
+) : MobileConnectionRepository, MobileConnectionRepositoryKairos {
+    /**
+     * Sets whether this connection is a typical mobile connection or a carrier merged connection.
+     */
+    fun setIsCarrierMerged(isCarrierMerged: Boolean) {
+        _isCarrierMerged.value = isCarrierMerged
+    }
+
+    /**
+     * Returns true if this repo is currently for a carrier merged connection and false otherwise.
+     */
+    @VisibleForTesting fun getIsCarrierMerged() = _isCarrierMerged.value
+
+    private val _isCarrierMerged = MutableStateFlow(startingIsCarrierMerged)
+    private val isCarrierMerged: StateFlow<Boolean> =
+        _isCarrierMerged
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = "isCarrierMerged",
+                initialValue = startingIsCarrierMerged,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), startingIsCarrierMerged)
+
+    private val mobileRepo: MobileConnectionRepository by lazy {
+        mobileRepoFactory.build(
+            subId,
+            tableLogBuffer,
+            subscriptionModel,
+            defaultNetworkName,
+            networkNameSeparator,
+        )
+    }
+
+    private val carrierMergedRepo: MobileConnectionRepository by lazy {
+        carrierMergedRepoFactory.build(subId, tableLogBuffer)
+    }
+
+    @VisibleForTesting
+    val activeRepo: StateFlow<MobileConnectionRepository> = run {
+        val initial =
+            if (startingIsCarrierMerged) {
+                carrierMergedRepo
+            } else {
+                mobileRepo
+            }
+
+        this.isCarrierMerged
+            .mapLatest { isCarrierMerged ->
+                if (isCarrierMerged) {
+                    carrierMergedRepo
+                } else {
+                    mobileRepo
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), initial)
+    }
+
+    override val carrierId =
+        activeRepo
+            .flatMapLatest { it.carrierId }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.carrierId.value)
+
+    override val cdmaRoaming =
+        activeRepo
+            .flatMapLatest { it.cdmaRoaming }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.cdmaRoaming.value)
+
+    override val isEmergencyOnly =
+        activeRepo
+            .flatMapLatest { it.isEmergencyOnly }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_EMERGENCY,
+                initialValue = activeRepo.value.isEmergencyOnly.value,
+            )
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                activeRepo.value.isEmergencyOnly.value,
+            )
+
+    override val isRoaming =
+        activeRepo
+            .flatMapLatest { it.isRoaming }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_ROAMING,
+                initialValue = activeRepo.value.isRoaming.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isRoaming.value)
+
+    override val operatorAlphaShort =
+        activeRepo
+            .flatMapLatest { it.operatorAlphaShort }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_OPERATOR,
+                initialValue = activeRepo.value.operatorAlphaShort.value,
+            )
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                activeRepo.value.operatorAlphaShort.value,
+            )
+
+    override val isInService =
+        activeRepo
+            .flatMapLatest { it.isInService }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_IS_IN_SERVICE,
+                initialValue = activeRepo.value.isInService.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isInService.value)
+
+    override val isNonTerrestrial =
+        activeRepo
+            .flatMapLatest { it.isNonTerrestrial }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_IS_NTN,
+                initialValue = activeRepo.value.isNonTerrestrial.value,
+            )
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                activeRepo.value.isNonTerrestrial.value,
+            )
+
+    override val isGsm =
+        activeRepo
+            .flatMapLatest { it.isGsm }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_IS_GSM,
+                initialValue = activeRepo.value.isGsm.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isGsm.value)
+
+    override val cdmaLevel =
+        activeRepo
+            .flatMapLatest { it.cdmaLevel }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_CDMA_LEVEL,
+                initialValue = activeRepo.value.cdmaLevel.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.cdmaLevel.value)
+
+    override val primaryLevel =
+        activeRepo
+            .flatMapLatest { it.primaryLevel }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_PRIMARY_LEVEL,
+                initialValue = activeRepo.value.primaryLevel.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.primaryLevel.value)
+
+    override val satelliteLevel: StateFlow<Int> =
+        activeRepo
+            .flatMapLatest { it.satelliteLevel }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_SATELLITE_LEVEL,
+                initialValue = activeRepo.value.satelliteLevel.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.satelliteLevel.value)
+
+    override val dataConnectionState =
+        activeRepo
+            .flatMapLatest { it.dataConnectionState }
+            .logDiffsForTable(
+                tableLogBuffer,
+                initialValue = activeRepo.value.dataConnectionState.value,
+            )
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                activeRepo.value.dataConnectionState.value,
+            )
+
+    override val dataActivityDirection =
+        activeRepo
+            .flatMapLatest { it.dataActivityDirection }
+            .logDiffsForTable(
+                tableLogBuffer,
+                initialValue = activeRepo.value.dataActivityDirection.value,
+            )
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                activeRepo.value.dataActivityDirection.value,
+            )
+
+    override val carrierNetworkChangeActive =
+        activeRepo
+            .flatMapLatest { it.carrierNetworkChangeActive }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = COL_CARRIER_NETWORK_CHANGE,
+                initialValue = activeRepo.value.carrierNetworkChangeActive.value,
+            )
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                activeRepo.value.carrierNetworkChangeActive.value,
+            )
+
+    override val resolvedNetworkType =
+        activeRepo
+            .flatMapLatest { it.resolvedNetworkType }
+            .logDiffsForTable(
+                tableLogBuffer,
+                initialValue = activeRepo.value.resolvedNetworkType.value,
+            )
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                activeRepo.value.resolvedNetworkType.value,
+            )
+
+    override val dataEnabled =
+        activeRepo
+            .flatMapLatest { it.dataEnabled }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = "dataEnabled",
+                initialValue = activeRepo.value.dataEnabled.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.dataEnabled.value)
+
+    override val inflateSignalStrength =
+        activeRepo
+            .flatMapLatest { it.inflateSignalStrength }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = "inflate",
+                initialValue = activeRepo.value.inflateSignalStrength.value,
+            )
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                activeRepo.value.inflateSignalStrength.value,
+            )
+
+    override val allowNetworkSliceIndicator =
+        activeRepo
+            .flatMapLatest { it.allowNetworkSliceIndicator }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnName = "allowSlice",
+                initialValue = activeRepo.value.allowNetworkSliceIndicator.value,
+            )
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                activeRepo.value.allowNetworkSliceIndicator.value,
+            )
+
+    override val numberOfLevels =
+        activeRepo
+            .flatMapLatest { it.numberOfLevels }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.numberOfLevels.value)
+
+    override val networkName =
+        activeRepo
+            .flatMapLatest { it.networkName }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "intent",
+                initialValue = activeRepo.value.networkName.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.networkName.value)
+
+    override val carrierName =
+        activeRepo
+            .flatMapLatest { it.carrierName }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "sub",
+                initialValue = activeRepo.value.carrierName.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.carrierName.value)
+
+    override val isAllowedDuringAirplaneMode =
+        activeRepo
+            .flatMapLatest { it.isAllowedDuringAirplaneMode }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                activeRepo.value.isAllowedDuringAirplaneMode.value,
+            )
+
+    override val hasPrioritizedNetworkCapabilities =
+        activeRepo
+            .flatMapLatest { it.hasPrioritizedNetworkCapabilities }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                activeRepo.value.hasPrioritizedNetworkCapabilities.value,
+            )
+
+    override suspend fun isInEcmMode(): Boolean = activeRepo.value.isInEcmMode()
+
+    fun dump(pw: PrintWriter) {
+        val ipw = IndentingPrintWriter(pw, "  ")
+
+        ipw.println("MobileConnectionRepository[$subId]")
+        ipw.increaseIndent()
+
+        ipw.println("carrierMerged=${_isCarrierMerged.value}")
+
+        ipw.print("Type (cellular or carrier merged): ")
+        when (activeRepo.value) {
+            is CarrierMergedConnectionRepository -> ipw.println("Carrier merged")
+            is MobileConnectionRepositoryImpl -> ipw.println("Cellular")
+        }
+
+        ipw.increaseIndent()
+        ipw.println("Provider: ${activeRepo.value}")
+        ipw.decreaseIndent()
+
+        ipw.decreaseIndent()
+    }
+
+    class Factory
+    @Inject
+    constructor(
+        @Background private val scope: CoroutineScope,
+        private val logFactory: TableLogBufferFactory,
+        private val mobileRepoFactory: MobileConnectionRepositoryImpl.Factory,
+        private val carrierMergedRepoFactory: CarrierMergedConnectionRepository.Factory,
+    ) {
+        fun build(
+            subId: Int,
+            startingIsCarrierMerged: Boolean,
+            subscriptionModel: Flow<SubscriptionModel?>,
+            defaultNetworkName: NetworkNameModel,
+            networkNameSeparator: String,
+        ): FullMobileConnectionRepositoryKairos {
+            val mobileLogger =
+                logFactory.getOrCreate(tableBufferLogName(subId), MOBILE_CONNECTION_BUFFER_SIZE)
+
+            return FullMobileConnectionRepositoryKairos(
+                subId,
+                startingIsCarrierMerged,
+                mobileLogger,
+                subscriptionModel,
+                defaultNetworkName,
+                networkNameSeparator,
+                scope,
+                mobileRepoFactory,
+                carrierMergedRepoFactory,
+            )
+        }
+
+        companion object {
+            /** The buffer size to use for logging. */
+            const val MOBILE_CONNECTION_BUFFER_SIZE = 100
+
+            /** Returns a log buffer name for a mobile connection with the given [subId]. */
+            fun tableBufferLogName(subId: Int): String = "MobileConnectionLog[$subId]"
+        }
+    }
+
+    companion object {
+        const val COL_CARRIER_ID = "carrierId"
+        const val COL_CARRIER_NETWORK_CHANGE = "carrierNetworkChangeActive"
+        const val COL_CDMA_LEVEL = "cdmaLevel"
+        const val COL_EMERGENCY = "emergencyOnly"
+        const val COL_IS_NTN = "isNtn"
+        const val COL_IS_GSM = "isGsm"
+        const val COL_IS_IN_SERVICE = "isInService"
+        const val COL_OPERATOR = "operatorName"
+        const val COL_PRIMARY_LEVEL = "primaryLevel"
+        const val COL_SATELLITE_LEVEL = "satelliteLevel"
+        const val COL_ROAMING = "roaming"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosImpl.kt
new file mode 100644
index 0000000..a074acd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosImpl.kt
@@ -0,0 +1,521 @@
+/*
+ * Copyright (C) 2022 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.prod
+
+import android.annotation.SuppressLint
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.net.ConnectivityManager
+import android.net.ConnectivityManager.NetworkCallback
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.net.NetworkRequest
+import android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
+import android.telephony.CellSignalStrengthCdma
+import android.telephony.ServiceState
+import android.telephony.SignalStrength
+import android.telephony.SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.TelephonyCallback
+import android.telephony.TelephonyDisplayInfo
+import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
+import android.telephony.TelephonyManager
+import android.telephony.TelephonyManager.ERI_FLASH
+import android.telephony.TelephonyManager.ERI_ON
+import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID
+import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
+import android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID
+import android.telephony.satellite.NtnSignalStrength
+import com.android.settingslib.Utils
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags.ROAMING_INDICATOR_VIA_DISPLAY_INFO
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Disconnected
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.model.toDataConnectionType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
+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.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.asExecutor
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.mapNotNull
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.scan
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
+
+/**
+ * A repository implementation for a typical mobile connection (as opposed to a carrier merged
+ * connection -- see [CarrierMergedConnectionRepository]).
+ */
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+class MobileConnectionRepositoryKairosImpl(
+    override val subId: Int,
+    private val context: Context,
+    subscriptionModel: Flow<SubscriptionModel?>,
+    defaultNetworkName: NetworkNameModel,
+    networkNameSeparator: String,
+    connectivityManager: ConnectivityManager,
+    private val telephonyManager: TelephonyManager,
+    systemUiCarrierConfig: SystemUiCarrierConfig,
+    broadcastDispatcher: BroadcastDispatcher,
+    private val mobileMappingsProxy: MobileMappingsProxy,
+    private val bgDispatcher: CoroutineDispatcher,
+    logger: MobileInputLogger,
+    override val tableLogBuffer: TableLogBuffer,
+    flags: FeatureFlagsClassic,
+    scope: CoroutineScope,
+) : MobileConnectionRepository, MobileConnectionRepositoryKairos {
+    init {
+        if (telephonyManager.subscriptionId != subId) {
+            throw IllegalStateException(
+                "MobileRepo: TelephonyManager should be created with subId($subId). " +
+                    "Found ${telephonyManager.subscriptionId} instead."
+            )
+        }
+    }
+
+    /**
+     * This flow defines the single shared connection to system_server via TelephonyCallback. Any
+     * new callback should be added to this listener and funneled through callbackEvents via a data
+     * class. See [CallbackEvent] for defining new callbacks.
+     *
+     * The reason we need to do this is because TelephonyManager limits the number of registered
+     * listeners per-process, so we don't want to create a new listener for every callback.
+     *
+     * A note on the design for back pressure here: We don't control _which_ telephony callback
+     * comes in first, since we register every relevant bit of information as a batch. E.g., if a
+     * downstream starts collecting on a field which is backed by
+     * [TelephonyCallback.ServiceStateListener], it's not possible for us to guarantee that _that_
+     * callback comes in -- the first callback could very well be
+     * [TelephonyCallback.DataActivityListener], which would promptly be dropped if we didn't keep
+     * it tracked. We use the [scan] operator here to track the most recent callback of _each type_
+     * here. See [TelephonyCallbackState] to see how the callbacks are stored.
+     */
+    private val callbackEvents: StateFlow<TelephonyCallbackState> = run {
+        val initial = TelephonyCallbackState()
+        callbackFlow {
+                val callback =
+                    object :
+                        TelephonyCallback(),
+                        TelephonyCallback.CarrierNetworkListener,
+                        TelephonyCallback.CarrierRoamingNtnListener,
+                        TelephonyCallback.DataActivityListener,
+                        TelephonyCallback.DataConnectionStateListener,
+                        TelephonyCallback.DataEnabledListener,
+                        TelephonyCallback.DisplayInfoListener,
+                        TelephonyCallback.ServiceStateListener,
+                        TelephonyCallback.SignalStrengthsListener {
+
+                        override fun onCarrierNetworkChange(active: Boolean) {
+                            logger.logOnCarrierNetworkChange(active, subId)
+                            trySend(CallbackEvent.OnCarrierNetworkChange(active))
+                        }
+
+                        override fun onCarrierRoamingNtnModeChanged(active: Boolean) {
+                            logger.logOnCarrierRoamingNtnModeChanged(active)
+                            trySend(CallbackEvent.OnCarrierRoamingNtnModeChanged(active))
+                        }
+
+                        override fun onDataActivity(direction: Int) {
+                            logger.logOnDataActivity(direction, subId)
+                            trySend(CallbackEvent.OnDataActivity(direction))
+                        }
+
+                        override fun onDataEnabledChanged(enabled: Boolean, reason: Int) {
+                            logger.logOnDataEnabledChanged(enabled, subId)
+                            trySend(CallbackEvent.OnDataEnabledChanged(enabled))
+                        }
+
+                        override fun onDataConnectionStateChanged(
+                            dataState: Int,
+                            networkType: Int,
+                        ) {
+                            logger.logOnDataConnectionStateChanged(dataState, networkType, subId)
+                            trySend(CallbackEvent.OnDataConnectionStateChanged(dataState))
+                        }
+
+                        override fun onDisplayInfoChanged(
+                            telephonyDisplayInfo: TelephonyDisplayInfo
+                        ) {
+                            logger.logOnDisplayInfoChanged(telephonyDisplayInfo, subId)
+                            trySend(CallbackEvent.OnDisplayInfoChanged(telephonyDisplayInfo))
+                        }
+
+                        override fun onServiceStateChanged(serviceState: ServiceState) {
+                            logger.logOnServiceStateChanged(serviceState, subId)
+                            trySend(CallbackEvent.OnServiceStateChanged(serviceState))
+                        }
+
+                        override fun onSignalStrengthsChanged(signalStrength: SignalStrength) {
+                            logger.logOnSignalStrengthsChanged(signalStrength, subId)
+                            trySend(CallbackEvent.OnSignalStrengthChanged(signalStrength))
+                        }
+
+                        override fun onCarrierRoamingNtnSignalStrengthChanged(
+                            signalStrength: NtnSignalStrength
+                        ) {
+                            logger.logNtnSignalStrengthChanged(signalStrength)
+                            trySend(
+                                CallbackEvent.OnCarrierRoamingNtnSignalStrengthChanged(
+                                    signalStrength
+                                )
+                            )
+                        }
+                    }
+                telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
+                awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
+            }
+            .flowOn(bgDispatcher)
+            .scan(initial = initial) { state, event -> state.applyEvent(event) }
+            .stateIn(scope = scope, started = SharingStarted.WhileSubscribed(), initial)
+    }
+
+    override val isEmergencyOnly =
+        callbackEvents
+            .mapNotNull { it.onServiceStateChanged }
+            .map { it.serviceState.isEmergencyOnly }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val isRoaming =
+        if (flags.isEnabled(ROAMING_INDICATOR_VIA_DISPLAY_INFO)) {
+                callbackEvents
+                    .mapNotNull { it.onDisplayInfoChanged }
+                    .map { it.telephonyDisplayInfo.isRoaming }
+            } else {
+                callbackEvents
+                    .mapNotNull { it.onServiceStateChanged }
+                    .map { it.serviceState.roaming }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val operatorAlphaShort =
+        callbackEvents
+            .mapNotNull { it.onServiceStateChanged }
+            .map { it.serviceState.operatorAlphaShort }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+    override val isInService =
+        callbackEvents
+            .mapNotNull { it.onServiceStateChanged }
+            .map { Utils.isInService(it.serviceState) }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val isNonTerrestrial =
+        callbackEvents
+            .mapNotNull { it.onCarrierRoamingNtnModeChanged }
+            .map { it.active }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val isGsm =
+        callbackEvents
+            .mapNotNull { it.onSignalStrengthChanged }
+            .map { it.signalStrength.isGsm }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val cdmaLevel =
+        callbackEvents
+            .mapNotNull { it.onSignalStrengthChanged }
+            .map {
+                it.signalStrength.getCellSignalStrengths(CellSignalStrengthCdma::class.java).let {
+                    strengths ->
+                    if (strengths.isNotEmpty()) {
+                        strengths[0].level
+                    } else {
+                        SIGNAL_STRENGTH_NONE_OR_UNKNOWN
+                    }
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+
+    override val primaryLevel =
+        callbackEvents
+            .mapNotNull { it.onSignalStrengthChanged }
+            .map { it.signalStrength.level }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+
+    override val satelliteLevel: StateFlow<Int> =
+        callbackEvents
+            .mapNotNull { it.onCarrierRoamingNtnSignalStrengthChanged }
+            .map { it.signalStrength.level }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), 0)
+
+    override val dataConnectionState =
+        callbackEvents
+            .mapNotNull { it.onDataConnectionStateChanged }
+            .map { it.dataState.toDataConnectionType() }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), Disconnected)
+
+    override val dataActivityDirection =
+        callbackEvents
+            .mapNotNull { it.onDataActivity }
+            .map { it.direction.toMobileDataActivityModel() }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                DataActivityModel(hasActivityIn = false, hasActivityOut = false),
+            )
+
+    override val carrierNetworkChangeActive =
+        callbackEvents
+            .mapNotNull { it.onCarrierNetworkChange }
+            .map { it.active }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val resolvedNetworkType =
+        callbackEvents
+            .mapNotNull { it.onDisplayInfoChanged }
+            .map {
+                if (it.telephonyDisplayInfo.overrideNetworkType != OVERRIDE_NETWORK_TYPE_NONE) {
+                    OverrideNetworkType(
+                        mobileMappingsProxy.toIconKeyOverride(
+                            it.telephonyDisplayInfo.overrideNetworkType
+                        )
+                    )
+                } else if (it.telephonyDisplayInfo.networkType != NETWORK_TYPE_UNKNOWN) {
+                    DefaultNetworkType(
+                        mobileMappingsProxy.toIconKey(it.telephonyDisplayInfo.networkType)
+                    )
+                } else {
+                    UnknownNetworkType
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), UnknownNetworkType)
+
+    override val inflateSignalStrength = systemUiCarrierConfig.shouldInflateSignalStrength
+    override val allowNetworkSliceIndicator = systemUiCarrierConfig.allowNetworkSliceIndicator
+
+    override val numberOfLevels =
+        inflateSignalStrength
+            .map { shouldInflate ->
+                if (shouldInflate) {
+                    DEFAULT_NUM_LEVELS + 1
+                } else {
+                    DEFAULT_NUM_LEVELS
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_NUM_LEVELS)
+
+    override val carrierName =
+        subscriptionModel
+            .map {
+                it?.let { model -> NetworkNameModel.SubscriptionDerived(model.carrierName) }
+                    ?: defaultNetworkName
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
+
+    /**
+     * There are a few cases where we will need to poll [TelephonyManager] so we can update some
+     * internal state where callbacks aren't provided. Any of those events should be merged into
+     * this flow, which can be used to trigger the polling.
+     */
+    private val telephonyPollingEvent: Flow<Unit> = callbackEvents.map { Unit }
+
+    override val cdmaRoaming: StateFlow<Boolean> =
+        telephonyPollingEvent
+            .mapLatest {
+                try {
+                    val cdmaEri = telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber
+                    cdmaEri == ERI_ON || cdmaEri == ERI_FLASH
+                } catch (e: UnsupportedOperationException) {
+                    // Handles the same as a function call failure
+                    false
+                }
+            }
+            .flowOn(bgDispatcher)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val carrierId =
+        broadcastDispatcher
+            .broadcastFlow(
+                filter =
+                    IntentFilter(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED),
+                map = { intent, _ -> intent },
+            )
+            .filter { intent ->
+                intent.getIntExtra(EXTRA_SUBSCRIPTION_ID, INVALID_SUBSCRIPTION_ID) == subId
+            }
+            .map { it.carrierId() }
+            .onStart {
+                // Make sure we get the initial carrierId
+                emit(telephonyManager.simCarrierId)
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), telephonyManager.simCarrierId)
+
+    /**
+     * BroadcastDispatcher does not handle sticky broadcasts, so we can't use it here. Note that we
+     * now use the [SharingStarted.Eagerly] strategy, because there have been cases where the sticky
+     * broadcast does not represent the correct state.
+     *
+     * See b/322432056 for context.
+     */
+    @SuppressLint("RegisterReceiverViaContext")
+    override val networkName: StateFlow<NetworkNameModel> =
+        conflatedCallbackFlow {
+                val receiver =
+                    object : BroadcastReceiver() {
+                        override fun onReceive(context: Context, intent: Intent) {
+                            if (
+                                intent.getIntExtra(
+                                    EXTRA_SUBSCRIPTION_INDEX,
+                                    INVALID_SUBSCRIPTION_ID,
+                                ) == subId
+                            ) {
+                                logger.logServiceProvidersUpdatedBroadcast(intent)
+                                trySend(
+                                    intent.toNetworkNameModel(networkNameSeparator)
+                                        ?: defaultNetworkName
+                                )
+                            }
+                        }
+                    }
+
+                context.registerReceiver(
+                    receiver,
+                    IntentFilter(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED),
+                )
+
+                awaitClose { context.unregisterReceiver(receiver) }
+            }
+            .flowOn(bgDispatcher)
+            .stateIn(scope, SharingStarted.Eagerly, defaultNetworkName)
+
+    override val dataEnabled = run {
+        val initial = telephonyManager.isDataConnectionAllowed
+        callbackEvents
+            .mapNotNull { it.onDataEnabledChanged }
+            .map { it.enabled }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), initial)
+    }
+
+    override suspend fun isInEcmMode(): Boolean =
+        withContext(bgDispatcher) { telephonyManager.emergencyCallbackMode }
+
+    /** Typical mobile connections aren't available during airplane mode. */
+    override val isAllowedDuringAirplaneMode = MutableStateFlow(false).asStateFlow()
+
+    /**
+     * Currently, a network with NET_CAPABILITY_PRIORITIZE_LATENCY is the only type of network that
+     * we consider to be a "network slice". _PRIORITIZE_BANDWIDTH may be added in the future. Any of
+     * these capabilities that are used here must also be represented in the
+     * self_certified_network_capabilities.xml config file
+     */
+    @SuppressLint("WrongConstant")
+    private val networkSliceRequest =
+        NetworkRequest.Builder()
+            .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY)
+            .setSubscriptionIds(setOf(subId))
+            .build()
+
+    @SuppressLint("MissingPermission")
+    override val hasPrioritizedNetworkCapabilities: StateFlow<Boolean> =
+        conflatedCallbackFlow {
+                // Our network callback listens only for this.subId && net_cap_prioritize_latency
+                // therefore our state is a simple mapping of whether or not that network exists
+                val callback =
+                    object : NetworkCallback() {
+                        override fun onAvailable(network: Network) {
+                            logger.logPrioritizedNetworkAvailable(network.netId)
+                            trySend(true)
+                        }
+
+                        override fun onLost(network: Network) {
+                            logger.logPrioritizedNetworkLost(network.netId)
+                            trySend(false)
+                        }
+                    }
+
+                connectivityManager.registerNetworkCallback(networkSliceRequest, callback)
+
+                awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
+            }
+            .flowOn(bgDispatcher)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    class Factory
+    @Inject
+    constructor(
+        private val context: Context,
+        private val broadcastDispatcher: BroadcastDispatcher,
+        private val connectivityManager: ConnectivityManager,
+        private val telephonyManager: TelephonyManager,
+        private val logger: MobileInputLogger,
+        private val carrierConfigRepository: CarrierConfigRepository,
+        private val mobileMappingsProxy: MobileMappingsProxy,
+        private val flags: FeatureFlagsClassic,
+        @Background private val bgDispatcher: CoroutineDispatcher,
+        @Background private val scope: CoroutineScope,
+    ) {
+        fun build(
+            subId: Int,
+            mobileLogger: TableLogBuffer,
+            subscriptionModel: Flow<SubscriptionModel?>,
+            defaultNetworkName: NetworkNameModel,
+            networkNameSeparator: String,
+        ): MobileConnectionRepositoryKairos {
+            return MobileConnectionRepositoryKairosImpl(
+                subId,
+                context,
+                subscriptionModel,
+                defaultNetworkName,
+                networkNameSeparator,
+                connectivityManager,
+                telephonyManager.createForSubscriptionId(subId),
+                carrierConfigRepository.getOrCreateConfigForSubId(subId),
+                broadcastDispatcher,
+                mobileMappingsProxy,
+                bgDispatcher,
+                logger,
+                mobileLogger,
+                flags,
+                scope,
+            )
+        }
+    }
+}
+
+private fun Intent.carrierId(): Int =
+    getIntExtra(TelephonyManager.EXTRA_CARRIER_ID, UNKNOWN_CARRIER_ID)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosImpl.kt
new file mode 100644
index 0000000..51771dd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosImpl.kt
@@ -0,0 +1,515 @@
+/*
+ * Copyright (C) 2022 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.prod
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.PackageManager
+import android.telephony.CarrierConfigManager
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.TelephonyCallback
+import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
+import android.telephony.TelephonyManager
+import android.util.IndentingPrintWriter
+import androidx.annotation.VisibleForTesting
+import com.android.internal.telephony.PhoneConstants
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.settingslib.mobile.MobileMappings.Config
+import com.android.systemui.Dumpable
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.mobile.util.SubscriptionManagerProxy
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.util.kotlin.pairwise
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import java.io.PrintWriter
+import java.lang.ref.WeakReference
+import java.util.concurrent.ConcurrentHashMap
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.asExecutor
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.mapNotNull
+import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
+
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@SysUISingleton
+class MobileConnectionsRepositoryKairosImpl
+@Inject
+constructor(
+    connectivityRepository: ConnectivityRepository,
+    private val subscriptionManager: SubscriptionManager,
+    private val subscriptionManagerProxy: SubscriptionManagerProxy,
+    private val telephonyManager: TelephonyManager,
+    private val logger: MobileInputLogger,
+    @MobileSummaryLog private val tableLogger: TableLogBuffer,
+    mobileMappingsProxy: MobileMappingsProxy,
+    broadcastDispatcher: BroadcastDispatcher,
+    private val context: Context,
+    @Background private val bgDispatcher: CoroutineDispatcher,
+    @Background private val scope: CoroutineScope,
+    @Main private val mainDispatcher: CoroutineDispatcher,
+    airplaneModeRepository: AirplaneModeRepository,
+    // Some "wifi networks" should be rendered as a mobile connection, which is why the wifi
+    // repository is an input to the mobile repository.
+    // See [CarrierMergedConnectionRepository] for details.
+    wifiRepository: WifiRepository,
+    private val fullMobileRepoFactory: FullMobileConnectionRepository.Factory,
+    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+    private val dumpManager: DumpManager,
+) : MobileConnectionsRepository, MobileConnectionsRepositoryKairos, Dumpable {
+
+    // TODO(b/333912012): for now, we are never invalidating the cache. We can do better though
+    private var subIdRepositoryCache =
+        ConcurrentHashMap<Int, WeakReference<FullMobileConnectionRepository>>()
+
+    private val defaultNetworkName =
+        NetworkNameModel.Default(
+            context.getString(com.android.internal.R.string.lockscreen_carrier_default)
+        )
+
+    private val networkNameSeparator: String =
+        context.getString(R.string.status_bar_network_name_separator)
+
+    init {
+        dumpManager.registerNormalDumpable("MobileConnectionsRepository", this)
+    }
+
+    private val carrierMergedSubId: StateFlow<Int?> =
+        combine(
+                wifiRepository.wifiNetwork,
+                connectivityRepository.defaultConnections,
+                airplaneModeRepository.isAirplaneMode,
+            ) { wifiNetwork, defaultConnections, isAirplaneMode ->
+                // The carrier merged connection should only be used if it's also the default
+                // connection or mobile connections aren't available because of airplane mode.
+                val defaultConnectionIsNonMobile =
+                    defaultConnections.carrierMerged.isDefault ||
+                        defaultConnections.wifi.isDefault ||
+                        isAirplaneMode
+
+                if (wifiNetwork is WifiNetworkModel.CarrierMerged && defaultConnectionIsNonMobile) {
+                    wifiNetwork.subscriptionId
+                } else {
+                    null
+                }
+            }
+            .distinctUntilChanged()
+            .logDiffsForTable(
+                tableLogger,
+                LOGGING_PREFIX,
+                columnName = "carrierMergedSubId",
+                initialValue = null,
+            )
+            .stateIn(scope, started = SharingStarted.WhileSubscribed(), null)
+
+    private val mobileSubscriptionsChangeEvent: Flow<Unit> =
+        conflatedCallbackFlow {
+                val callback =
+                    object : SubscriptionManager.OnSubscriptionsChangedListener() {
+                        override fun onSubscriptionsChanged() {
+                            logger.logOnSubscriptionsChanged()
+                            trySend(Unit)
+                        }
+                    }
+
+                subscriptionManager.addOnSubscriptionsChangedListener(
+                    bgDispatcher.asExecutor(),
+                    callback,
+                )
+
+                awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(callback) }
+            }
+            .flowOn(bgDispatcher)
+
+    /** Turn ACTION_SERVICE_STATE (for subId = -1) into an event */
+    private val serviceStateChangedEvent: Flow<Unit> =
+        broadcastDispatcher
+            .broadcastFlow(IntentFilter(Intent.ACTION_SERVICE_STATE)) { intent, _ ->
+                val subId =
+                    intent.getIntExtra(
+                        SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
+                        INVALID_SUBSCRIPTION_ID,
+                    )
+
+                // Only emit if the subId is not associated with an active subscription
+                if (subId == INVALID_SUBSCRIPTION_ID) {
+                    Unit
+                }
+            }
+            // Emit on start so that we always check the state at least once
+            .onStart { emit(Unit) }
+
+    /** Eager flow to determine the device-based emergency calls only state */
+    override val isDeviceEmergencyCallCapable: StateFlow<Boolean> =
+        serviceStateChangedEvent
+            .mapLatest {
+                val modems = telephonyManager.activeModemCount
+
+                // Assume false for automotive devices which don't have the calling feature.
+                // TODO: b/398045526 to revisit the below.
+                val isAutomotive: Boolean =
+                    context.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+                val hasFeatureCalling: Boolean =
+                    context.packageManager.hasSystemFeature(
+                        PackageManager.FEATURE_TELEPHONY_CALLING
+                    )
+                if (isAutomotive && !hasFeatureCalling) {
+                    return@mapLatest false
+                }
+
+                // Check the service state for every modem. If any state reports emergency calling
+                // capable, then consider the device to have emergency call capabilities
+                (0..<modems)
+                    .map { telephonyManager.getServiceStateForSlot(it) }
+                    .any { it?.isEmergencyOnly == true }
+            }
+            .flowOn(bgDispatcher)
+            .distinctUntilChanged()
+            .logDiffsForTable(
+                tableLogger,
+                columnPrefix = LOGGING_PREFIX,
+                columnName = "deviceEmergencyOnly",
+                initialValue = false,
+            )
+            .stateIn(scope, SharingStarted.Eagerly, false)
+
+    /**
+     * State flow that emits the set of mobile data subscriptions, each represented by its own
+     * [SubscriptionModel].
+     */
+    override val subscriptions: StateFlow<List<SubscriptionModel>> =
+        merge(mobileSubscriptionsChangeEvent, carrierMergedSubId)
+            .mapLatest { fetchSubscriptionsList().map { it.toSubscriptionModel() } }
+            .onEach { infos -> updateRepos(infos) }
+            .distinctUntilChanged()
+            .logDiffsForTable(
+                tableLogger,
+                LOGGING_PREFIX,
+                columnName = "subscriptions",
+                initialValue = listOf(),
+            )
+            .stateIn(scope, started = SharingStarted.WhileSubscribed(), listOf())
+
+    override val activeMobileDataSubscriptionId: StateFlow<Int?> =
+        conflatedCallbackFlow {
+                val callback =
+                    object : TelephonyCallback(), ActiveDataSubscriptionIdListener {
+                        override fun onActiveDataSubscriptionIdChanged(subId: Int) {
+                            if (subId != INVALID_SUBSCRIPTION_ID) {
+                                trySend(subId)
+                            } else {
+                                trySend(null)
+                            }
+                        }
+                    }
+
+                telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
+                awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
+            }
+            .flowOn(bgDispatcher)
+            .distinctUntilChanged()
+            .logDiffsForTable(
+                tableLogger,
+                LOGGING_PREFIX,
+                columnName = "activeSubId",
+                initialValue = null,
+            )
+            .stateIn(scope, started = SharingStarted.WhileSubscribed(), null)
+
+    override val activeMobileDataRepository =
+        activeMobileDataSubscriptionId
+            .map { activeSubId ->
+                if (activeSubId == null) {
+                    null
+                } else {
+                    getOrCreateRepoForSubId(activeSubId)
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+    override val defaultDataSubId: StateFlow<Int?> =
+        broadcastDispatcher
+            .broadcastFlow(
+                IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+            ) { intent, _ ->
+                val subId =
+                    intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID)
+                if (subId == INVALID_SUBSCRIPTION_ID) {
+                    null
+                } else {
+                    subId
+                }
+            }
+            .distinctUntilChanged()
+            .logDiffsForTable(
+                tableLogger,
+                LOGGING_PREFIX,
+                columnName = "defaultSubId",
+                initialValue = null,
+            )
+            .onStart {
+                val subId = subscriptionManagerProxy.getDefaultDataSubscriptionId()
+                emit(if (subId == INVALID_SUBSCRIPTION_ID) null else subId)
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+    private val carrierConfigChangedEvent =
+        broadcastDispatcher
+            .broadcastFlow(IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED))
+            .onEach { logger.logActionCarrierConfigChanged() }
+
+    override val defaultDataSubRatConfig: StateFlow<Config> =
+        merge(defaultDataSubId, carrierConfigChangedEvent)
+            .onStart { emit(Unit) }
+            .mapLatest { Config.readConfig(context) }
+            .distinctUntilChanged()
+            .onEach { logger.logDefaultDataSubRatConfig(it) }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                initialValue = Config.readConfig(context),
+            )
+
+    override val defaultMobileIconMapping: Flow<Map<String, MobileIconGroup>> =
+        defaultDataSubRatConfig
+            .map { mobileMappingsProxy.mapIconSets(it) }
+            .distinctUntilChanged()
+            .onEach { logger.logDefaultMobileIconMapping(it) }
+
+    override val defaultMobileIconGroup: Flow<MobileIconGroup> =
+        defaultDataSubRatConfig
+            .map { mobileMappingsProxy.getDefaultIcons(it) }
+            .distinctUntilChanged()
+            .onEach { logger.logDefaultMobileIconGroup(it) }
+
+    override val isAnySimSecure: Flow<Boolean> =
+        conflatedCallbackFlow {
+                val callback =
+                    object : KeyguardUpdateMonitorCallback() {
+                        override fun onSimStateChanged(subId: Int, slotId: Int, simState: Int) {
+                            logger.logOnSimStateChanged()
+                            trySend(getIsAnySimSecure())
+                        }
+                    }
+                keyguardUpdateMonitor.registerCallback(callback)
+                trySend(false)
+                awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
+            }
+            .flowOn(mainDispatcher)
+            .logDiffsForTable(
+                tableLogger,
+                LOGGING_PREFIX,
+                columnName = "isAnySimSecure",
+                initialValue = false,
+            )
+            .distinctUntilChanged()
+
+    override fun getIsAnySimSecure() = keyguardUpdateMonitor.isSimPinSecure
+
+    override fun getRepoForSubId(subId: Int): FullMobileConnectionRepository =
+        getOrCreateRepoForSubId(subId)
+
+    private fun getOrCreateRepoForSubId(subId: Int) =
+        subIdRepositoryCache[subId]?.get()
+            ?: createRepositoryForSubId(subId).also {
+                subIdRepositoryCache[subId] = WeakReference(it)
+            }
+
+    override val mobileIsDefault: StateFlow<Boolean> =
+        connectivityRepository.defaultConnections
+            .map { it.mobile.isDefault }
+            .distinctUntilChanged()
+            .logDiffsForTable(
+                tableLogger,
+                columnPrefix = LOGGING_PREFIX,
+                columnName = "mobileIsDefault",
+                initialValue = false,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val hasCarrierMergedConnection: StateFlow<Boolean> =
+        carrierMergedSubId
+            .map { it != null }
+            .distinctUntilChanged()
+            .logDiffsForTable(
+                tableLogger,
+                columnPrefix = LOGGING_PREFIX,
+                columnName = "hasCarrierMergedConnection",
+                initialValue = false,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val defaultConnectionIsValidated: StateFlow<Boolean> =
+        connectivityRepository.defaultConnections
+            .map { it.isValidated }
+            .distinctUntilChanged()
+            .logDiffsForTable(
+                tableLogger,
+                columnName = "defaultConnectionIsValidated",
+                initialValue = false,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    /**
+     * Flow that tracks the active mobile data subscriptions. Emits `true` whenever the active data
+     * subscription Id changes but the subscription group remains the same. In these cases, we want
+     * to retain the previous subscription's validation status for up to 2s to avoid flickering the
+     * icon.
+     *
+     * TODO(b/265164432): we should probably expose all change events, not just same group
+     */
+    @SuppressLint("MissingPermission")
+    override val activeSubChangedInGroupEvent =
+        activeMobileDataSubscriptionId
+            .pairwise()
+            .mapNotNull { (prevVal: Int?, newVal: Int?) ->
+                if (prevVal == null || newVal == null) return@mapNotNull null
+
+                val prevSub = subscriptionManager.getActiveSubscriptionInfo(prevVal)?.groupUuid
+                val nextSub = subscriptionManager.getActiveSubscriptionInfo(newVal)?.groupUuid
+
+                if (prevSub != null && prevSub == nextSub) Unit else null
+            }
+            .flowOn(bgDispatcher)
+
+    override suspend fun isInEcmMode(): Boolean {
+        if (telephonyManager.emergencyCallbackMode) {
+            return true
+        }
+        return with(subscriptions.value) {
+            any { getOrCreateRepoForSubId(it.subscriptionId).isInEcmMode() }
+        }
+    }
+
+    private fun isValidSubId(subId: Int): Boolean = checkSub(subId, subscriptions.value)
+
+    @VisibleForTesting fun getSubIdRepoCache() = subIdRepositoryCache
+
+    private fun subscriptionModelForSubId(subId: Int): Flow<SubscriptionModel?> {
+        return subscriptions.map { list ->
+            list.firstOrNull { model -> model.subscriptionId == subId }
+        }
+    }
+
+    private fun createRepositoryForSubId(subId: Int): FullMobileConnectionRepository {
+        return fullMobileRepoFactory.build(
+            subId,
+            isCarrierMerged(subId),
+            subscriptionModelForSubId(subId),
+            defaultNetworkName,
+            networkNameSeparator,
+        )
+    }
+
+    private fun updateRepos(newInfos: List<SubscriptionModel>) {
+        subIdRepositoryCache.forEach { (subId, repo) ->
+            repo.get()?.setIsCarrierMerged(isCarrierMerged(subId))
+        }
+    }
+
+    private fun isCarrierMerged(subId: Int): Boolean {
+        return subId == carrierMergedSubId.value
+    }
+
+    /**
+     * True if the checked subId is in the list of current subs or the active mobile data subId
+     *
+     * @param checkedSubs the list to validate [subId] against. To invalidate the cache, pass in the
+     *   new subscription list. Otherwise use [subscriptions.value] to validate a subId against the
+     *   current known subscriptions
+     */
+    private fun checkSub(subId: Int, checkedSubs: List<SubscriptionModel>): Boolean {
+        if (activeMobileDataSubscriptionId.value == subId) return true
+
+        checkedSubs.forEach {
+            if (it.subscriptionId == subId) {
+                return true
+            }
+        }
+
+        return false
+    }
+
+    private suspend fun fetchSubscriptionsList(): List<SubscriptionInfo> =
+        withContext(bgDispatcher) { subscriptionManager.completeActiveSubscriptionInfoList }
+
+    private fun SubscriptionInfo.toSubscriptionModel(): SubscriptionModel =
+        SubscriptionModel(
+            subscriptionId = subscriptionId,
+            isOpportunistic = isOpportunistic,
+            isExclusivelyNonTerrestrial = isOnlyNonTerrestrialNetwork,
+            groupUuid = groupUuid,
+            carrierName = carrierName.toString(),
+            profileClass = profileClass,
+        )
+
+    override fun dump(pw: PrintWriter, args: Array<String>) {
+        val ipw = IndentingPrintWriter(pw, " ")
+        ipw.println("Connection cache:")
+
+        ipw.increaseIndent()
+        subIdRepositoryCache.entries.forEach { (subId, repo) ->
+            ipw.println("$subId: ${repo.get()}")
+        }
+        ipw.decreaseIndent()
+
+        ipw.println("Connections (${subIdRepositoryCache.size} total):")
+        ipw.increaseIndent()
+        subIdRepositoryCache.values.forEach { it.get()?.dump(ipw) }
+        ipw.decreaseIndent()
+    }
+
+    companion object {
+        private const val LOGGING_PREFIX = "Repo"
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt
index df74404..db948e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.pipeline.mobile.data.model
 
 import android.os.PersistableBundle
-import android.telephony.CarrierConfigManager
 import android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL
 import android.telephony.CarrierConfigManager.KEY_SHOW_5G_SLICE_ICON_BOOL
 import android.telephony.CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL
@@ -37,7 +36,7 @@
 
     @Before
     fun setUp() {
-        underTest = SystemUiCarrierConfig(SUB_1_ID, createTestConfig())
+        underTest = SystemUiCarrierConfig(SUB_1_ID, testCarrierConfig())
     }
 
     @Test
@@ -46,7 +45,7 @@
         assertThat(underTest.isUsingDefault).isTrue()
 
         // ANY new config means we're no longer tracking defaults
-        underTest.processNewCarrierConfig(createTestConfig())
+        underTest.processNewCarrierConfig(testCarrierConfig())
 
         assertThat(underTest.isUsingDefault).isFalse()
     }
@@ -58,7 +57,7 @@
         assertThat(underTest.allowNetworkSliceIndicator.value).isTrue()
 
         underTest.processNewCarrierConfig(
-            configWithOverrides(
+            testCarrierConfigWithOverrides(
                 KEY_INFLATE_SIGNAL_STRENGTH_BOOL to true,
                 KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL to true,
                 KEY_SHOW_5G_SLICE_ICON_BOOL to false,
@@ -81,11 +80,11 @@
         underTest =
             SystemUiCarrierConfig(
                 SUB_1_ID,
-                configWithOverrides(
+                testCarrierConfigWithOverrides(
                     KEY_INFLATE_SIGNAL_STRENGTH_BOOL to true,
                     KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL to true,
                     KEY_SHOW_5G_SLICE_ICON_BOOL to true,
-                )
+                ),
             )
 
         assertThat(underTest.isUsingDefault).isTrue()
@@ -104,26 +103,5 @@
 
     companion object {
         private const val SUB_1_ID = 1
-
-        /**
-         * In order to keep us from having to update every place that might want to create a config,
-         * make sure to add new keys here
-         */
-        fun createTestConfig() =
-            PersistableBundle().also {
-                it.putBoolean(CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
-                it.putBoolean(CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL, false)
-                it.putBoolean(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 =
-            createTestConfig().also { it.putBoolean(key, override) }
-
-        /** Override any number of configs from the default */
-        fun configWithOverrides(vararg overrides: Pair<String, Boolean>) =
-            createTestConfig().also { config ->
-                overrides.forEach { (key, value) -> config.putBoolean(key, value) }
-            }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImplTest.kt
index d074fc2..e1cc259 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImplTest.kt
@@ -26,7 +26,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
-import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfig
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.launchIn
@@ -163,8 +163,8 @@
         private const val SUB_ID_1 = 1
         private const val SUB_ID_2 = 2
 
-        private val DEFAULT_CONFIG = createTestConfig()
-        private val CONFIG_1 = createTestConfig()
-        private val CONFIG_2 = createTestConfig()
+        private val DEFAULT_CONFIG = testCarrierConfig()
+        private val CONFIG_1 = testCarrierConfig()
+        private val CONFIG_2 = testCarrierConfig()
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index a51e919..ed8be9b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -86,8 +86,8 @@
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
-import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.configWithOverride
-import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfigWithOverride
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.signalStrength
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.telephonyDisplayInfo
@@ -129,7 +129,7 @@
     @Mock private lateinit var context: Context
 
     private val mobileMappings = FakeMobileMappingsProxy()
-    private val systemUiCarrierConfig = SystemUiCarrierConfig(SUB_1_ID, createTestConfig())
+    private val systemUiCarrierConfig = SystemUiCarrierConfig(SUB_1_ID, testCarrierConfig())
 
     private val testDispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(testDispatcher)
@@ -1314,13 +1314,13 @@
             assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS)
 
             systemUiCarrierConfig.processNewCarrierConfig(
-                configWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true)
+                testCarrierConfigWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true)
             )
 
             assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS + 1)
 
             systemUiCarrierConfig.processNewCarrierConfig(
-                configWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
+                testCarrierConfigWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
             )
 
             assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS)
@@ -1336,13 +1336,13 @@
             assertThat(latest).isEqualTo(false)
 
             systemUiCarrierConfig.processNewCarrierConfig(
-                configWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true)
+                testCarrierConfigWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true)
             )
 
             assertThat(latest).isEqualTo(true)
 
             systemUiCarrierConfig.processNewCarrierConfig(
-                configWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
+                testCarrierConfigWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
             )
 
             assertThat(latest).isEqualTo(false)
@@ -1354,13 +1354,13 @@
             val latest by collectLastValue(underTest.allowNetworkSliceIndicator)
 
             systemUiCarrierConfig.processNewCarrierConfig(
-                configWithOverride(KEY_SHOW_5G_SLICE_ICON_BOOL, true)
+                testCarrierConfigWithOverride(KEY_SHOW_5G_SLICE_ICON_BOOL, true)
             )
 
             assertThat(latest).isTrue()
 
             systemUiCarrierConfig.processNewCarrierConfig(
-                configWithOverride(KEY_SHOW_5G_SLICE_ICON_BOOL, false)
+                testCarrierConfigWithOverride(KEY_SHOW_5G_SLICE_ICON_BOOL, false)
             )
 
             assertThat(latest).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
index ec260fc..6f21e79 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
@@ -41,7 +41,7 @@
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
-import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest
+import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfig
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.getTelephonyCallbackForType
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.signalStrength
 import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
@@ -105,11 +105,7 @@
     @Mock private lateinit var subscriptionModel: StateFlow<SubscriptionModel?>
 
     private val mobileMappings = FakeMobileMappingsProxy()
-    private val systemUiCarrierConfig =
-        SystemUiCarrierConfig(
-            SUB_1_ID,
-            SystemUiCarrierConfigTest.createTestConfig(),
-        )
+    private val systemUiCarrierConfig = SystemUiCarrierConfig(SUB_1_ID, testCarrierConfig())
 
     private val testDispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(testDispatcher)
@@ -185,12 +181,7 @@
             val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this)
 
             assertThat(latest)
-                .isEqualTo(
-                    DataActivityModel(
-                        hasActivityIn = true,
-                        hasActivityOut = true,
-                    )
-                )
+                .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true))
 
             displayInfoJob.cancel()
             job.cancel()
@@ -209,7 +200,7 @@
 
             connectionCallback.onDataConnectionStateChanged(
                 TelephonyManager.DATA_CONNECTED,
-                200 /* unused */
+                200, /* unused */
             )
 
             flipActivity(100, activityCallback)
@@ -320,10 +311,7 @@
             job.cancel()
         }
 
-    private fun flipActivity(
-        times: Int,
-        callback: DataActivityListener,
-    ) {
+    private fun flipActivity(times: Int, callback: DataActivityListener) {
         repeat(times) { index -> callback.onDataActivity(index % 4) }
     }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigFakes.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigFakes.kt
new file mode 100644
index 0000000..13b01634
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigFakes.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2025 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.model
+
+import android.os.PersistableBundle
+import android.telephony.CarrierConfigManager
+
+/**
+ * In order to keep us from having to update every place that might want to create a config, make
+ * sure to add new keys here
+ */
+fun testCarrierConfig() =
+    PersistableBundle().also {
+        it.putBoolean(CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
+        it.putBoolean(CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL, false)
+        it.putBoolean(CarrierConfigManager.KEY_SHOW_5G_SLICE_ICON_BOOL, true)
+    }
+
+/** Override the default config with the given (key, value) pair */
+fun testCarrierConfigWithOverride(key: String, override: Boolean): PersistableBundle =
+    testCarrierConfig().also { it.putBoolean(key, override) }
+
+/** Override any number of configs from the default */
+fun testCarrierConfigWithOverrides(vararg overrides: Pair<String, Boolean>) =
+    testCarrierConfig().also { config ->
+        overrides.forEach { (key, value) -> config.putBoolean(key, value) }
+    }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeSubscriptionManagerProxy.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeSubscriptionManagerProxy.kt
similarity index 93%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeSubscriptionManagerProxy.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeSubscriptionManagerProxy.kt
index a802381..5b70907 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeSubscriptionManagerProxy.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeSubscriptionManagerProxy.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 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.
@@ -23,7 +23,7 @@
 class FakeSubscriptionManagerProxy(
     /** Set the default data subId to be returned in [getDefaultDataSubscriptionId] */
     var defaultDataSubId: Int = INVALID_SUBSCRIPTION_ID,
-    var activeSubscriptionInfo: SubscriptionInfo? = null
+    var activeSubscriptionInfo: SubscriptionInfo? = null,
 ) : SubscriptionManagerProxy {
     override fun getDefaultDataSubscriptionId(): Int = defaultDataSubId