1 /* <lambda>null2 * Copyright (C) 2025 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar.pipeline.mobile.domain.interactor 18 19 import androidx.test.ext.junit.runners.AndroidJUnit4 20 import androidx.test.filters.SmallTest 21 import com.android.settingslib.SignalIcon 22 import com.android.settingslib.mobile.MobileIconCarrierIdOverrides 23 import com.android.systemui.activated 24 import com.android.systemui.kairos.BuildScope 25 import com.android.systemui.kairos.ExperimentalKairosApi 26 import com.android.systemui.kairos.Incremental 27 import com.android.systemui.kairos.State 28 import com.android.systemui.kairos.asIncremental 29 import com.android.systemui.kairos.buildSpec 30 import com.android.systemui.kairos.combine 31 import com.android.systemui.kairos.launchKairosNetwork 32 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel 33 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorKairosAdapterTest.Companion.wrapRepo 34 import com.android.systemui.util.mockito.mock 35 import kotlinx.coroutines.ExperimentalCoroutinesApi 36 import kotlinx.coroutines.Job 37 import kotlinx.coroutines.launch 38 import kotlinx.coroutines.test.runCurrent 39 import org.junit.runner.RunWith 40 41 @OptIn(ExperimentalKairosApi::class, ExperimentalCoroutinesApi::class) 42 @SmallTest 43 @RunWith(AndroidJUnit4::class) 44 class MobileIconInteractorKairosAdapterTest : MobileIconInteractorTestBase() { 45 46 var job: Job? = null 47 val kairosNetwork = testScope.backgroundScope.launchKairosNetwork() 48 49 override fun createInteractor(overrides: MobileIconCarrierIdOverrides): MobileIconInteractor { 50 lateinit var result: MobileIconInteractor 51 job?.cancel() 52 job = 53 testScope.backgroundScope.launch { 54 kairosNetwork.activateSpec { 55 val wrapped = wrap(mobileIconsInteractor) 56 result = 57 MobileIconInteractorKairosAdapter( 58 kairosImpl = 59 activated { 60 MobileIconInteractorKairosImpl( 61 defaultSubscriptionHasDataEnabled = 62 wrapped.activeDataConnectionHasDataEnabled, 63 alwaysShowDataRatIcon = wrapped.alwaysShowDataRatIcon, 64 alwaysUseCdmaLevel = wrapped.alwaysUseCdmaLevel, 65 isSingleCarrier = wrapped.isSingleCarrier, 66 mobileIsDefault = wrapped.mobileIsDefault, 67 defaultMobileIconMapping = wrapped.defaultMobileIconMapping, 68 defaultMobileIconGroup = wrapped.defaultMobileIconGroup, 69 isDefaultConnectionFailed = 70 wrapped.isDefaultConnectionFailed, 71 isForceHidden = wrapped.isForceHidden, 72 connectionRepository = wrapRepo(connectionRepository), 73 context = context, 74 carrierIdOverrides = overrides, 75 ) 76 } 77 ) 78 Unit 79 } 80 } 81 testScope.runCurrent() // ensure the lateinit is set 82 return result 83 } 84 85 /** Allows us to wrap a (likely fake) MobileIconsInteractor into a Kairos version. */ 86 private fun BuildScope.wrap(interactor: MobileIconsInteractor): MobileIconsInteractorKairos { 87 val filteredSubscriptions = interactor.filteredSubscriptions.toState(emptyList()) 88 val icons = interactor.icons.toState() 89 return InteractorWrapper( 90 mobileIsDefault = interactor.mobileIsDefault.toState(), 91 filteredSubscriptions = filteredSubscriptions, 92 icons = 93 combine(filteredSubscriptions, icons) { subs, icons -> 94 subs.zip(icons).associate { (subModel, icon) -> 95 subModel.subscriptionId to buildSpec { wrap(icon) } 96 } 97 } 98 .asIncremental() 99 .applyLatestSpecForKey(), 100 isStackable = interactor.isStackable.toState(false), 101 activeDataConnectionHasDataEnabled = 102 interactor.activeDataConnectionHasDataEnabled.toState(), 103 activeDataIconInteractor = 104 interactor.activeDataIconInteractor.toState().mapLatestBuild { 105 it?.let { wrap(it) } 106 }, 107 alwaysShowDataRatIcon = interactor.alwaysShowDataRatIcon.toState(), 108 alwaysUseCdmaLevel = interactor.alwaysUseCdmaLevel.toState(), 109 isSingleCarrier = interactor.isSingleCarrier.toState(), 110 defaultMobileIconMapping = interactor.defaultMobileIconMapping.toState(), 111 defaultMobileIconGroup = interactor.defaultMobileIconGroup.toState(), 112 isDefaultConnectionFailed = interactor.isDefaultConnectionFailed.toState(), 113 isUserSetUp = interactor.isUserSetUp.toState(), 114 isForceHidden = interactor.isForceHidden.toState(false), 115 isDeviceInEmergencyCallsOnlyMode = 116 interactor.isDeviceInEmergencyCallsOnlyMode.toState(false), 117 ) 118 } 119 120 private fun BuildScope.wrap(interactor: MobileIconInteractor): MobileIconInteractorKairos = 121 // unused in tests 122 mock() 123 124 private class InteractorWrapper( 125 override val mobileIsDefault: State<Boolean>, 126 override val filteredSubscriptions: State<List<SubscriptionModel>>, 127 override val icons: Incremental<Int, MobileIconInteractorKairos>, 128 override val isStackable: State<Boolean>, 129 override val activeDataConnectionHasDataEnabled: State<Boolean>, 130 override val activeDataIconInteractor: State<MobileIconInteractorKairos?>, 131 override val alwaysShowDataRatIcon: State<Boolean>, 132 override val alwaysUseCdmaLevel: State<Boolean>, 133 override val isSingleCarrier: State<Boolean>, 134 override val defaultMobileIconMapping: State<Map<String, SignalIcon.MobileIconGroup>>, 135 override val defaultMobileIconGroup: State<SignalIcon.MobileIconGroup>, 136 override val isDefaultConnectionFailed: State<Boolean>, 137 override val isUserSetUp: State<Boolean>, 138 override val isForceHidden: State<Boolean>, 139 override val isDeviceInEmergencyCallsOnlyMode: State<Boolean>, 140 ) : MobileIconsInteractorKairos 141 } 142