1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel 18 19 import androidx.test.filters.SmallTest 20 import com.android.systemui.R 21 import com.android.systemui.SysuiTestCase 22 import com.android.systemui.common.shared.model.Text 23 import com.android.systemui.coroutines.collectLastValue 24 import com.android.systemui.log.table.TableLogBuffer 25 import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon 26 import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository 27 import com.android.systemui.statusbar.pipeline.ethernet.domain.EthernetInteractor 28 import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState 29 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel 30 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository 31 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository 32 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository 33 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor 34 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl 35 import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy 36 import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel 37 import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository 38 import com.android.systemui.statusbar.pipeline.shared.ui.model.SignalIcon 39 import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.InternetTileViewModel.Companion.NOT_CONNECTED_NETWORKS_UNAVAILABLE 40 import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository 41 import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractorImpl 42 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel 43 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry 44 import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon 45 import com.android.systemui.util.CarrierConfigTracker 46 import com.android.systemui.util.mockito.mock 47 import com.google.common.truth.Truth.assertThat 48 import kotlinx.coroutines.test.TestScope 49 import kotlinx.coroutines.test.runTest 50 import org.junit.Before 51 import org.junit.Test 52 53 @SmallTest 54 class InternetTileViewModelTest : SysuiTestCase() { 55 private lateinit var underTest: InternetTileViewModel 56 private lateinit var mobileIconsInteractor: MobileIconsInteractor 57 58 private val airplaneModeRepository = FakeAirplaneModeRepository() 59 private val connectivityRepository = FakeConnectivityRepository() 60 private val ethernetInteractor = EthernetInteractor(connectivityRepository) 61 private val wifiRepository = FakeWifiRepository() 62 private val userSetupRepo = FakeUserSetupRepository() 63 private val testScope = TestScope() 64 private val wifiInteractor = 65 WifiInteractorImpl(connectivityRepository, wifiRepository, testScope.backgroundScope) 66 67 private val tableLogBuffer: TableLogBuffer = mock() 68 private val carrierConfigTracker: CarrierConfigTracker = mock() 69 70 private val mobileConnectionsRepository = 71 FakeMobileConnectionsRepository(FakeMobileMappingsProxy(), tableLogBuffer) 72 private val mobileConnectionRepository = 73 FakeMobileConnectionRepository(SUB_1_ID, tableLogBuffer) 74 75 @Before 76 fun setUp() { 77 mobileConnectionRepository.apply { 78 setNetworkTypeKey(mobileConnectionsRepository.GSM_KEY) 79 isInService.value = true 80 dataConnectionState.value = DataConnectionState.Connected 81 dataEnabled.value = true 82 } 83 84 mobileConnectionsRepository.apply { 85 activeMobileDataRepository.value = mobileConnectionRepository 86 activeMobileDataSubscriptionId.value = SUB_1_ID 87 setMobileConnectionRepositoryMap(mapOf(SUB_1_ID to mobileConnectionRepository)) 88 } 89 90 mobileIconsInteractor = 91 MobileIconsInteractorImpl( 92 mobileConnectionsRepository, 93 carrierConfigTracker, 94 tableLogBuffer, 95 connectivityRepository, 96 userSetupRepo, 97 testScope.backgroundScope, 98 context, 99 ) 100 101 underTest = 102 InternetTileViewModel( 103 airplaneModeRepository, 104 connectivityRepository, 105 ethernetInteractor, 106 mobileIconsInteractor, 107 wifiInteractor, 108 context, 109 testScope.backgroundScope, 110 ) 111 } 112 113 @Test 114 fun noDefault_noNetworksAvailable() = 115 testScope.runTest { 116 val latest by collectLastValue(underTest.tileModel) 117 118 connectivityRepository.defaultConnections.value = DefaultConnectionModel() 119 120 assertThat(latest?.secondaryLabel) 121 .isEqualTo(Text.Resource(R.string.quick_settings_networks_unavailable)) 122 assertThat(latest?.iconId).isEqualTo(R.drawable.ic_qs_no_internet_unavailable) 123 } 124 125 @Test 126 fun noDefault_networksAvailable() = 127 testScope.runTest { 128 // TODO: support [WifiInteractor.areNetworksAvailable] 129 } 130 131 @Test 132 fun wifiDefaultAndActive() = 133 testScope.runTest { 134 val latest by collectLastValue(underTest.tileModel) 135 136 val networkModel = 137 WifiNetworkModel.Active( 138 networkId = 1, 139 level = 4, 140 ssid = "test ssid", 141 ) 142 143 connectivityRepository.setWifiConnected() 144 wifiRepository.setIsWifiDefault(true) 145 wifiRepository.setWifiNetwork(networkModel) 146 147 // Type is [Visible] since that is the only model that stores a resId 148 val expectedIcon: WifiIcon.Visible = 149 WifiIcon.fromModel(networkModel, context) as WifiIcon.Visible 150 151 assertThat(latest?.secondaryTitle).isEqualTo("test ssid") 152 assertThat(latest?.secondaryLabel).isNull() 153 assertThat(latest?.icon).isEqualTo(ResourceIcon.get(expectedIcon.icon.res)) 154 assertThat(latest?.iconId).isNull() 155 } 156 157 @Test 158 fun wifiDefaultAndNotActive_noNetworksAvailable() = 159 testScope.runTest { 160 val latest by collectLastValue(underTest.tileModel) 161 162 val networkModel = WifiNetworkModel.Inactive 163 164 connectivityRepository.setWifiConnected(validated = false) 165 wifiRepository.setIsWifiDefault(true) 166 wifiRepository.setWifiNetwork(networkModel) 167 wifiRepository.wifiScanResults.value = emptyList() 168 169 assertThat(latest).isEqualTo(NOT_CONNECTED_NETWORKS_UNAVAILABLE) 170 } 171 172 @Test 173 fun wifiDefaultAndNotActive_networksAvailable() = 174 testScope.runTest { 175 val latest by collectLastValue(underTest.tileModel) 176 177 val networkModel = WifiNetworkModel.Inactive 178 179 connectivityRepository.setWifiConnected(validated = false) 180 wifiRepository.setIsWifiDefault(true) 181 wifiRepository.setWifiNetwork(networkModel) 182 wifiRepository.wifiScanResults.value = listOf(WifiScanEntry("test 1")) 183 184 assertThat(latest?.secondaryLabel).isNull() 185 assertThat(latest?.secondaryTitle) 186 .isEqualTo(context.getString(R.string.quick_settings_networks_available)) 187 assertThat(latest?.icon).isNull() 188 assertThat(latest?.iconId).isEqualTo(R.drawable.ic_qs_no_internet_available) 189 } 190 191 @Test 192 fun mobileDefault_usesNetworkNameAndIcon() = 193 testScope.runTest { 194 val latest by collectLastValue(underTest.tileModel) 195 196 connectivityRepository.setMobileConnected() 197 mobileConnectionsRepository.mobileIsDefault.value = true 198 mobileConnectionRepository.apply { 199 setAllLevels(3) 200 setAllRoaming(false) 201 networkName.value = NetworkNameModel.Default("test network") 202 } 203 204 assertThat(latest?.secondaryTitle).contains("test network") 205 assertThat(latest?.secondaryLabel).isNull() 206 assertThat(latest?.icon).isInstanceOf(SignalIcon::class.java) 207 assertThat(latest?.iconId).isNull() 208 } 209 210 @Test 211 fun ethernetDefault_validated_matchesInteractor() = 212 testScope.runTest { 213 val latest by collectLastValue(underTest.tileModel) 214 val ethernetIcon by collectLastValue(ethernetInteractor.icon) 215 216 connectivityRepository.setEthernetConnected(default = true, validated = true) 217 218 assertThat(latest?.secondaryLabel).isNull() 219 assertThat(latest?.secondaryTitle) 220 .isEqualTo(ethernetIcon!!.contentDescription.toString()) 221 assertThat(latest?.iconId).isEqualTo(R.drawable.stat_sys_ethernet_fully) 222 assertThat(latest?.icon).isNull() 223 } 224 225 @Test 226 fun ethernetDefault_notValidated_matchesInteractor() = 227 testScope.runTest { 228 val latest by collectLastValue(underTest.tileModel) 229 val ethernetIcon by collectLastValue(ethernetInteractor.icon) 230 231 connectivityRepository.setEthernetConnected(default = true, validated = false) 232 233 assertThat(latest?.secondaryLabel).isNull() 234 assertThat(latest?.secondaryTitle) 235 .isEqualTo(ethernetIcon!!.contentDescription.toString()) 236 assertThat(latest?.iconId).isEqualTo(R.drawable.stat_sys_ethernet) 237 assertThat(latest?.icon).isNull() 238 } 239 240 companion object { 241 const val SUB_1_ID = 1 242 } 243 } 244