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