1 /* 2 * Copyright (C) 2021 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.connectivity; 18 19 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; 20 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 21 22 import static junit.framework.Assert.assertEquals; 23 24 import static org.junit.Assert.assertTrue; 25 import static org.mockito.ArgumentMatchers.anyLong; 26 import static org.mockito.Mockito.mock; 27 import static org.mockito.Mockito.when; 28 29 import android.content.Intent; 30 import android.net.ConnectivityManager; 31 import android.net.Network; 32 import android.net.NetworkCapabilities; 33 import android.net.NetworkInfo; 34 import android.net.vcn.VcnTransportInfo; 35 import android.net.wifi.WifiInfo; 36 import android.net.wifi.WifiManager; 37 import android.testing.TestableLooper.RunWithLooper; 38 39 import androidx.test.ext.junit.runners.AndroidJUnit4; 40 import androidx.test.filters.SmallTest; 41 42 import com.android.settingslib.mobile.TelephonyIcons; 43 44 import org.junit.Before; 45 import org.junit.Test; 46 import org.junit.runner.RunWith; 47 import org.mockito.ArgumentCaptor; 48 import org.mockito.Mockito; 49 50 import java.util.Collections; 51 52 @SmallTest 53 @RunWith(AndroidJUnit4.class) 54 @RunWithLooper 55 public class NetworkControllerWifiTest extends NetworkControllerBaseTest { 56 // These match the constants in WifiManager and need to be kept up to date. 57 private static final int MIN_RSSI = -100; 58 private static final int MAX_RSSI = -55; 59 private WifiInfo mWifiInfo = mock(WifiInfo.class); 60 private VcnTransportInfo mVcnTransportInfo = mock(VcnTransportInfo.class); 61 62 @Before setUp()63 public void setUp() throws Exception { 64 super.setUp(); 65 allowTestableLooperAsMainThread(); 66 when(mWifiInfo.makeCopy(anyLong())).thenReturn(mWifiInfo); 67 when(mWifiInfo.isPrimary()).thenReturn(true); 68 } 69 70 @Test testWifiIcon()71 public void testWifiIcon() { 72 String testSsid = "Test SSID"; 73 setWifiEnabled(true); 74 verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK); 75 76 setWifiState(true, testSsid); 77 setWifiLevel(0); 78 79 // Connected, but still not validated - does not show 80 verifyLastWifiIcon(false, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]); 81 82 for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) { 83 setWifiLevel(testLevel); 84 85 setConnectivityViaCallbackInNetworkController( 86 NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo); 87 verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]); 88 setConnectivityViaCallbackInNetworkController( 89 NetworkCapabilities.TRANSPORT_WIFI, false, true, mWifiInfo); 90 // Icon does not show if not validated 91 verifyLastWifiIcon(false, WifiIcons.WIFI_SIGNAL_STRENGTH[0][testLevel]); 92 } 93 } 94 95 @Test testQsWifiIcon()96 public void testQsWifiIcon() { 97 String testSsid = "Test SSID"; 98 99 setWifiEnabled(false); 100 verifyLastQsWifiIcon(false, false, WifiIcons.QS_WIFI_NO_NETWORK, null); 101 102 setWifiEnabled(true); 103 verifyLastQsWifiIcon(true, false, WifiIcons.QS_WIFI_NO_NETWORK, null); 104 105 setWifiState(true, testSsid); 106 for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) { 107 setWifiLevel(testLevel); 108 setConnectivityViaCallbackInNetworkController( 109 NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo); 110 setConnectivityViaDefaultCallbackInWifiTracker( 111 NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo); 112 verifyLastQsWifiIcon(true, true, WifiIcons.QS_WIFI_SIGNAL_STRENGTH[1][testLevel], 113 testSsid); 114 setConnectivityViaCallbackInNetworkController( 115 NetworkCapabilities.TRANSPORT_WIFI, false, true, mWifiInfo); 116 verifyLastQsWifiIcon(true, true, WifiIcons.QS_WIFI_SIGNAL_STRENGTH[0][testLevel], 117 testSsid); 118 } 119 } 120 121 @Test testQsDataDirection()122 public void testQsDataDirection() { 123 // Setup normal connection 124 String testSsid = "Test SSID"; 125 int testLevel = 2; 126 setWifiEnabled(true); 127 setWifiState(true, testSsid); 128 setWifiLevel(testLevel); 129 setConnectivityViaCallbackInNetworkController( 130 NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo); 131 setConnectivityViaDefaultCallbackInWifiTracker( 132 NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo); 133 verifyLastQsWifiIcon(true, true, 134 WifiIcons.QS_WIFI_SIGNAL_STRENGTH[1][testLevel], testSsid); 135 136 // Set to different activity state first to ensure a callback happens. 137 setWifiActivity(WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN); 138 139 setWifiActivity(WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE); 140 verifyLastQsDataDirection(false, false); 141 setWifiActivity(WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN); 142 verifyLastQsDataDirection(true, false); 143 setWifiActivity(WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT); 144 verifyLastQsDataDirection(false, true); 145 setWifiActivity(WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT); 146 verifyLastQsDataDirection(true, true); 147 } 148 149 @Test testRoamingIconDuringWifi()150 public void testRoamingIconDuringWifi() { 151 // Setup normal connection 152 String testSsid = "Test SSID"; 153 int testLevel = 2; 154 setWifiEnabled(true); 155 setWifiState(true, testSsid); 156 setWifiLevel(testLevel); 157 setConnectivityViaCallbackInNetworkController( 158 NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo); 159 verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]); 160 161 setupDefaultSignal(); 162 setGsmRoaming(true); 163 // Still be on wifi though. 164 setConnectivityViaCallbackInNetworkController( 165 NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo); 166 setConnectivityViaCallbackInNetworkController( 167 NetworkCapabilities.TRANSPORT_CELLULAR, false, false, null); 168 verifyLastMobileDataIndicators(true, DEFAULT_LEVEL, 0, true); 169 } 170 171 @Test testWifiIconInvalidatedViaCallback()172 public void testWifiIconInvalidatedViaCallback() { 173 // Setup normal connection 174 String testSsid = "Test SSID"; 175 int testLevel = 2; 176 setWifiEnabled(true); 177 setWifiState(true, testSsid); 178 setWifiLevel(testLevel); 179 setConnectivityViaCallbackInNetworkController( 180 NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo); 181 verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]); 182 183 setConnectivityViaCallbackInNetworkController( 184 NetworkCapabilities.TRANSPORT_WIFI, false, true, mWifiInfo); 185 verifyLastWifiIcon(false, WifiIcons.WIFI_SIGNAL_STRENGTH[0][testLevel]); 186 } 187 188 @Test testWifiIconDisconnectedViaCallback()189 public void testWifiIconDisconnectedViaCallback() { 190 // Setup normal connection 191 String testSsid = "Test SSID"; 192 int testLevel = 2; 193 setWifiEnabled(true); 194 setWifiState(true, testSsid); 195 setWifiLevel(testLevel); 196 setConnectivityViaCallbackInNetworkController( 197 NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo); 198 verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]); 199 200 setWifiState(false, testSsid); 201 setConnectivityViaCallbackInNetworkController( 202 NetworkCapabilities.TRANSPORT_WIFI, false, false, mWifiInfo); 203 verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK); 204 } 205 206 @Test testVpnWithUnderlyingWifi()207 public void testVpnWithUnderlyingWifi() { 208 String testSsid = "Test SSID"; 209 int testLevel = 2; 210 setWifiEnabled(true); 211 verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK); 212 213 setConnectivityViaCallbackInNetworkController( 214 NetworkCapabilities.TRANSPORT_VPN, false, true, mWifiInfo); 215 setConnectivityViaCallbackInNetworkController( 216 NetworkCapabilities.TRANSPORT_VPN, true, true, mWifiInfo); 217 verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK); 218 219 // Mock calling setUnderlyingNetworks. 220 setWifiState(true, testSsid); 221 setWifiLevel(testLevel); 222 setConnectivityViaCallbackInNetworkController( 223 NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo); 224 verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]); 225 } 226 227 @Test testFetchInitialData()228 public void testFetchInitialData() { 229 mNetworkController.mWifiSignalController.fetchInitialState(); 230 Mockito.verify(mMockWm).getWifiState(); 231 Mockito.verify(mMockCm).getNetworkInfo(ConnectivityManager.TYPE_WIFI); 232 } 233 234 @Test testFetchInitialData_correctValues()235 public void testFetchInitialData_correctValues() { 236 String testSsid = "TEST"; 237 238 when(mMockWm.getWifiState()).thenReturn(WifiManager.WIFI_STATE_ENABLED); 239 NetworkInfo networkInfo = mock(NetworkInfo.class); 240 when(networkInfo.isConnected()).thenReturn(true); 241 when(mMockCm.getNetworkInfo(ConnectivityManager.TYPE_WIFI)).thenReturn(networkInfo); 242 WifiInfo wifiInfo = mock(WifiInfo.class); 243 when(wifiInfo.getSSID()).thenReturn(testSsid); 244 when(mMockWm.getConnectionInfo()).thenReturn(wifiInfo); 245 246 mNetworkController.mWifiSignalController.fetchInitialState(); 247 248 assertTrue(mNetworkController.mWifiSignalController.mCurrentState.enabled); 249 assertTrue(mNetworkController.mWifiSignalController.mCurrentState.connected); 250 assertEquals(testSsid, mNetworkController.mWifiSignalController.mCurrentState.ssid); 251 } 252 253 @Test testVcnWithUnderlyingWifi()254 public void testVcnWithUnderlyingWifi() { 255 String testSsid = "Test VCN SSID"; 256 setWifiEnabled(true); 257 verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK); 258 259 mNetworkController.setNoNetworksAvailable(false); 260 setWifiStateForVcn(true, testSsid); 261 setWifiLevelForVcn(0); 262 verifyLastMobileDataIndicatorsForVcn(true, 0, TelephonyIcons.ICON_CWF, false); 263 264 mNetworkController.setNoNetworksAvailable(true); 265 for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) { 266 setWifiLevelForVcn(testLevel); 267 268 setConnectivityViaCallbackInNetworkControllerForVcn( 269 NetworkCapabilities.TRANSPORT_CELLULAR, true, true, mVcnTransportInfo); 270 verifyLastMobileDataIndicatorsForVcn(true, testLevel, TelephonyIcons.ICON_CWF, true); 271 272 setConnectivityViaCallbackInNetworkControllerForVcn( 273 NetworkCapabilities.TRANSPORT_CELLULAR, false, true, mVcnTransportInfo); 274 verifyLastMobileDataIndicatorsForVcn(true, testLevel, TelephonyIcons.ICON_CWF, false); 275 } 276 } 277 278 /** Test for b/225902574. */ 279 @Test vcnOnlyOnUnderlyingNetwork()280 public void vcnOnlyOnUnderlyingNetwork() { 281 setWifiEnabled(true); 282 283 // Set up a carrier merged network... 284 WifiInfo underlyingCarrierMergedInfo = Mockito.mock(WifiInfo.class); 285 when(underlyingCarrierMergedInfo.isCarrierMerged()).thenReturn(true); 286 when(underlyingCarrierMergedInfo.isPrimary()).thenReturn(true); 287 int zeroLevel = 0; 288 when(underlyingCarrierMergedInfo.getRssi()).thenReturn(calculateRssiForLevel(zeroLevel)); 289 290 NetworkCapabilities underlyingNetworkCapabilities = Mockito.mock(NetworkCapabilities.class); 291 when(underlyingNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) 292 .thenReturn(true); 293 when(underlyingNetworkCapabilities.getTransportInfo()) 294 .thenReturn(underlyingCarrierMergedInfo); 295 296 Network underlyingNetwork = Mockito.mock(Network.class); 297 when(mMockCm.getNetworkCapabilities(underlyingNetwork)) 298 .thenReturn(underlyingNetworkCapabilities); 299 300 NetworkCapabilities.Builder mainCapabilitiesBuilder = new NetworkCapabilities.Builder(); 301 mainCapabilitiesBuilder.addTransportType(TRANSPORT_CELLULAR); 302 mainCapabilitiesBuilder.setTransportInfo(null); 303 // And make the carrier merged network the underlying network, *not* the main network. 304 mainCapabilitiesBuilder.setUnderlyingNetworks(Collections.singletonList(underlyingNetwork)); 305 306 Network primaryNetwork = Mockito.mock(Network.class); 307 int primaryNetworkId = 1; 308 when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId); 309 310 // WHEN this primary network with underlying carrier merged information is sent 311 setConnectivityViaDefaultAndNormalCallbackInWifiTracker( 312 primaryNetwork, mainCapabilitiesBuilder.build()); 313 314 // THEN we see the mobile data indicators for carrier merged 315 verifyLastMobileDataIndicatorsForVcn( 316 /* visible= */ true, 317 /* level= */ zeroLevel, 318 TelephonyIcons.ICON_CWF, 319 /* inet= */ false); 320 321 // For each level... 322 for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) { 323 int rssi = calculateRssiForLevel(testLevel); 324 when(underlyingCarrierMergedInfo.getRssi()).thenReturn(rssi); 325 // WHEN the new level is sent to the callbacks 326 setConnectivityViaDefaultAndNormalCallbackInWifiTracker( 327 primaryNetwork, mainCapabilitiesBuilder.build()); 328 329 // WHEN the network is validated 330 mainCapabilitiesBuilder.addCapability(NET_CAPABILITY_VALIDATED); 331 setConnectivityViaCallbackInNetworkController( 332 primaryNetwork, mainCapabilitiesBuilder.build()); 333 334 // THEN we see the mobile data indicators with inet=true (no exclamation mark) 335 verifyLastMobileDataIndicatorsForVcn( 336 /* visible= */ true, 337 testLevel, 338 TelephonyIcons.ICON_CWF, 339 /* inet= */ true); 340 341 // WHEN the network is not validated 342 mainCapabilitiesBuilder.removeCapability(NET_CAPABILITY_VALIDATED); 343 setConnectivityViaCallbackInNetworkController( 344 primaryNetwork, mainCapabilitiesBuilder.build()); 345 346 // THEN we see the mobile data indicators with inet=false (exclamation mark) 347 verifyLastMobileDataIndicatorsForVcn( 348 /* visible= */ true, 349 testLevel, 350 TelephonyIcons.ICON_CWF, 351 /* inet= */ false); 352 } 353 } 354 355 @Test testDisableWiFiWithVcnWithUnderlyingWifi()356 public void testDisableWiFiWithVcnWithUnderlyingWifi() { 357 String testSsid = "Test VCN SSID"; 358 setWifiEnabled(true); 359 verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK); 360 361 mNetworkController.setNoNetworksAvailable(false); 362 setWifiStateForVcn(true, testSsid); 363 setWifiLevelForVcn(1); 364 verifyLastMobileDataIndicatorsForVcn(true, 1, TelephonyIcons.ICON_CWF, false); 365 366 setWifiEnabled(false); 367 verifyLastMobileDataIndicatorsForVcn(false, 1, 0, false); 368 } 369 setWifiActivity(int activity)370 protected void setWifiActivity(int activity) { 371 // TODO: Not this, because this variable probably isn't sticking around. 372 mNetworkController.mWifiSignalController.setActivity(activity); 373 } 374 setWifiLevel(int level)375 protected void setWifiLevel(int level) { 376 when(mWifiInfo.getRssi()).thenReturn(calculateRssiForLevel(level)); 377 setConnectivityViaCallbackInWifiTracker( 378 NetworkCapabilities.TRANSPORT_WIFI, false, true, mWifiInfo); 379 } 380 setWifiEnabled(boolean enabled)381 protected void setWifiEnabled(boolean enabled) { 382 when(mMockWm.getWifiState()).thenReturn( 383 enabled ? WifiManager.WIFI_STATE_ENABLED : WifiManager.WIFI_STATE_DISABLED); 384 mNetworkController.onReceive(mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION)); 385 } 386 setWifiState(boolean connected, String ssid)387 protected void setWifiState(boolean connected, String ssid) { 388 when(mWifiInfo.getSSID()).thenReturn(ssid); 389 setConnectivityViaCallbackInWifiTracker( 390 NetworkCapabilities.TRANSPORT_WIFI, false, connected, mWifiInfo); 391 } 392 setWifiLevelForVcn(int level)393 protected void setWifiLevelForVcn(int level) { 394 when(mVcnTransportInfo.getWifiInfo()).thenReturn(mWifiInfo); 395 when(mVcnTransportInfo.makeCopy(anyLong())).thenReturn(mVcnTransportInfo); 396 when(mWifiInfo.getRssi()).thenReturn(calculateRssiForLevel(level)); 397 when(mWifiInfo.isCarrierMerged()).thenReturn(true); 398 when(mWifiInfo.getSubscriptionId()).thenReturn(1); 399 setConnectivityViaCallbackInWifiTrackerForVcn( 400 NetworkCapabilities.TRANSPORT_CELLULAR, false, true, mVcnTransportInfo); 401 } 402 calculateRssiForLevel(int level)403 private int calculateRssiForLevel(int level) { 404 float amountPerLevel = (MAX_RSSI - MIN_RSSI) / (WifiIcons.WIFI_LEVEL_COUNT - 1); 405 int rssi = (int) (MIN_RSSI + level * amountPerLevel); 406 // Put RSSI in the middle of the range. 407 rssi += amountPerLevel / 2; 408 return rssi; 409 } 410 setWifiStateForVcn(boolean connected, String ssid)411 protected void setWifiStateForVcn(boolean connected, String ssid) { 412 when(mVcnTransportInfo.getWifiInfo()).thenReturn(mWifiInfo); 413 when(mVcnTransportInfo.makeCopy(anyLong())).thenReturn(mVcnTransportInfo); 414 when(mWifiInfo.getSSID()).thenReturn(ssid); 415 when(mWifiInfo.isCarrierMerged()).thenReturn(true); 416 when(mWifiInfo.getSubscriptionId()).thenReturn(1); 417 setConnectivityViaCallbackInWifiTrackerForVcn( 418 NetworkCapabilities.TRANSPORT_CELLULAR, false, connected, mVcnTransportInfo); 419 } 420 verifyLastQsDataDirection(boolean in, boolean out)421 protected void verifyLastQsDataDirection(boolean in, boolean out) { 422 ArgumentCaptor<WifiIndicators> indicatorsArg = 423 ArgumentCaptor.forClass(WifiIndicators.class); 424 425 Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators( 426 indicatorsArg.capture()); 427 WifiIndicators expected = indicatorsArg.getValue(); 428 assertEquals("WiFi data in, in quick settings", in, expected.activityIn); 429 assertEquals("WiFi data out, in quick settings", out, expected.activityOut); 430 } 431 verifyLastQsWifiIcon(boolean enabled, boolean connected, int icon, String description)432 protected void verifyLastQsWifiIcon(boolean enabled, boolean connected, int icon, 433 String description) { 434 ArgumentCaptor<WifiIndicators> indicatorsArg = 435 ArgumentCaptor.forClass(WifiIndicators.class); 436 437 Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators( 438 indicatorsArg.capture()); 439 WifiIndicators expected = indicatorsArg.getValue(); 440 assertEquals("WiFi enabled, in quick settings", enabled, expected.enabled); 441 assertEquals("WiFI desc (ssid), in quick settings", description, expected.description); 442 if (enabled && connected) { 443 assertEquals("WiFi connected, in quick settings", connected, expected.qsIcon.visible); 444 assertEquals("WiFi signal, in quick settings", icon, expected.qsIcon.icon); 445 } else { 446 assertEquals("WiFi is not default", null, expected.qsIcon); 447 } 448 } 449 verifyLastWifiIcon(boolean visible, int icon)450 protected void verifyLastWifiIcon(boolean visible, int icon) { 451 ArgumentCaptor<WifiIndicators> indicatorsArg = 452 ArgumentCaptor.forClass(WifiIndicators.class); 453 454 Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setWifiIndicators( 455 indicatorsArg.capture()); 456 WifiIndicators expected = indicatorsArg.getValue(); 457 assertEquals("WiFi visible, in status bar", visible, expected.statusIcon.visible); 458 assertEquals("WiFi signal, in status bar", icon, expected.statusIcon.icon); 459 } 460 } 461