1 /* 2 * Copyright (C) 2020 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.wifitrackerlib; 18 19 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; 20 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; 21 22 import static com.google.common.truth.Truth.assertThat; 23 24 import static org.mockito.ArgumentMatchers.any; 25 import static org.mockito.Mockito.mock; 26 import static org.mockito.Mockito.spy; 27 import static org.mockito.Mockito.times; 28 import static org.mockito.Mockito.when; 29 30 import android.content.Context; 31 import android.content.res.Resources; 32 import android.net.ConnectivityDiagnosticsManager; 33 import android.net.ConnectivityManager; 34 import android.net.Network; 35 import android.net.NetworkCapabilities; 36 import android.net.wifi.WifiConfiguration; 37 import android.net.wifi.WifiInfo; 38 import android.net.wifi.WifiManager; 39 import android.net.wifi.hotspot2.PasspointConfiguration; 40 import android.net.wifi.hotspot2.pps.Credential; 41 import android.net.wifi.hotspot2.pps.HomeSp; 42 import android.os.Handler; 43 import android.os.test.TestLooper; 44 45 import org.junit.Before; 46 import org.junit.Test; 47 import org.mockito.Mock; 48 import org.mockito.Mockito; 49 import org.mockito.MockitoAnnotations; 50 import org.mockito.MockitoSession; 51 52 import java.util.Arrays; 53 54 public class PasspointWifiEntryTest { 55 @Mock private WifiTrackerInjector mMockInjector; 56 @Mock private Context mMockContext; 57 @Mock private WifiManager mMockWifiManager; 58 @Mock private Resources mMockResources; 59 @Mock private WifiInfo mMockWifiInfo; 60 @Mock private Network mMockNetwork; 61 @Mock private NetworkCapabilities mMockNetworkCapabilities; 62 @Mock private ConnectivityManager mMockConnectivityManager; 63 64 private TestLooper mTestLooper; 65 private Handler mTestHandler; 66 67 private static final String FQDN = "fqdn"; 68 69 @Before setUp()70 public void setUp() { 71 MockitoAnnotations.initMocks(this); 72 73 mTestLooper = new TestLooper(); 74 mTestHandler = new Handler(mTestLooper.getLooper()); 75 76 when(mMockWifiInfo.isPrimary()).thenReturn(true); 77 when(mMockWifiInfo.getNetworkId()).thenReturn(WifiConfiguration.INVALID_NETWORK_ID); 78 when(mMockWifiInfo.getRssi()).thenReturn(WifiInfo.INVALID_RSSI); 79 when(mMockNetworkCapabilities.getTransportInfo()).thenReturn(mMockWifiInfo); 80 when(mMockInjector.getContext()).thenReturn(mMockContext); 81 when(mMockContext.getResources()).thenReturn(mMockResources); 82 when(mMockContext.getString(R.string.wifitrackerlib_summary_separator)).thenReturn("/"); 83 84 when(mMockContext.getSystemService(ConnectivityManager.class)) 85 .thenReturn(mMockConnectivityManager); 86 } 87 88 @Test testGetSummary_expiredTimeNotAvailable_notShowExpired()89 public void testGetSummary_expiredTimeNotAvailable_notShowExpired() { 90 // default SubscriptionExpirationTimeInMillis is unset 91 PasspointConfiguration passpointConfiguration = getPasspointConfiguration(); 92 String expired = "Expired"; 93 when(mMockContext.getString(R.string.wifitrackerlib_wifi_passpoint_expired)) 94 .thenReturn(expired); 95 96 PasspointWifiEntry passpointWifiEntry = new PasspointWifiEntry(mMockInjector, 97 mTestHandler, passpointConfiguration, mMockWifiManager, 98 false /* forSavedNetworksPage */); 99 100 assertThat(passpointWifiEntry.getSummary()).isNotEqualTo(expired); 101 } 102 103 @Test testGetSummary_expired_showExpired()104 public void testGetSummary_expired_showExpired() { 105 PasspointConfiguration passpointConfiguration = getPasspointConfiguration(); 106 String expired = "Expired"; 107 when(mMockContext.getString(R.string.wifitrackerlib_wifi_passpoint_expired)) 108 .thenReturn(expired); 109 PasspointWifiEntry passpointWifiEntry = new PasspointWifiEntry(mMockInjector, 110 mTestHandler, passpointConfiguration, mMockWifiManager, 111 false /* forSavedNetworksPage */); 112 PasspointWifiEntry spyEntry = spy(passpointWifiEntry); 113 when(spyEntry.isExpired()).thenReturn(true); 114 115 assertThat(spyEntry.getSummary()).isEqualTo(expired); 116 } 117 getPasspointConfiguration()118 private PasspointConfiguration getPasspointConfiguration() { 119 PasspointConfiguration passpointConfiguration = new PasspointConfiguration(); 120 HomeSp homeSp = new HomeSp(); 121 homeSp.setFqdn(FQDN); 122 passpointConfiguration.setHomeSp(homeSp); 123 passpointConfiguration.setCredential(new Credential()); 124 return passpointConfiguration; 125 } 126 127 @Test testGetMeteredChoice_afterSetMeteredChoice_getCorrectValue()128 public void testGetMeteredChoice_afterSetMeteredChoice_getCorrectValue() { 129 PasspointWifiEntry entry = new PasspointWifiEntry(mMockInjector, mTestHandler, 130 getPasspointConfiguration(), mMockWifiManager, 131 false /* forSavedNetworksPage */); 132 133 entry.setMeteredChoice(WifiEntry.METERED_CHOICE_UNMETERED); 134 135 assertThat(entry.getMeteredChoice()).isEqualTo(WifiEntry.METERED_CHOICE_UNMETERED); 136 } 137 138 @Test testGetSummary_connectedWifiNetwork_showsConnected()139 public void testGetSummary_connectedWifiNetwork_showsConnected() { 140 String summarySeparator = " / "; 141 String[] wifiStatusArray = new String[]{"", "Scanning", "Connecting", 142 "Authenticating", "Obtaining IP address", "Connected"}; 143 144 when(mMockContext.getString(R.string.wifitrackerlib_summary_separator)) 145 .thenReturn(summarySeparator); 146 when(mMockResources.getStringArray(R.array.wifitrackerlib_wifi_status)) 147 .thenReturn(wifiStatusArray); 148 when(mMockWifiInfo.isPasspointAp()).thenReturn(true); 149 when(mMockWifiInfo.getPasspointFqdn()).thenReturn(FQDN); 150 when(mMockWifiInfo.getPasspointUniqueId()).thenReturn( 151 getPasspointConfiguration().getUniqueId()); 152 when(mMockNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) 153 .thenReturn(true); 154 155 PasspointWifiEntry entry = new PasspointWifiEntry(mMockInjector, mTestHandler, 156 getPasspointConfiguration(), mMockWifiManager, 157 false /* forSavedNetworksPage */); 158 entry.onNetworkCapabilitiesChanged(mMockNetwork, mMockNetworkCapabilities); 159 entry.onDefaultNetworkCapabilitiesChanged(mMockNetwork, mMockNetworkCapabilities); 160 161 assertThat(entry.getSummary()).isEqualTo("Connected"); 162 } 163 164 @Test testGetSummary_connectedButNotDefault_doesNotShowConnected()165 public void testGetSummary_connectedButNotDefault_doesNotShowConnected() { 166 String summarySeparator = " / "; 167 String[] wifiStatusArray = new String[]{"", "Scanning", "Connecting", 168 "Authenticating", "Obtaining IP address", "Connected"}; 169 170 when(mMockContext.getString(R.string.wifitrackerlib_summary_separator)) 171 .thenReturn(summarySeparator); 172 when(mMockResources.getStringArray(R.array.wifitrackerlib_wifi_status)) 173 .thenReturn(wifiStatusArray); 174 when(mMockWifiInfo.isPasspointAp()).thenReturn(true); 175 when(mMockWifiInfo.getPasspointFqdn()).thenReturn(FQDN); 176 when(mMockWifiInfo.getPasspointUniqueId()).thenReturn( 177 getPasspointConfiguration().getUniqueId()); 178 when(mMockNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) 179 .thenReturn(true); 180 181 PasspointWifiEntry entry = new PasspointWifiEntry(mMockInjector, mTestHandler, 182 getPasspointConfiguration(), mMockWifiManager, 183 false /* forSavedNetworksPage */); 184 entry.onNetworkCapabilitiesChanged(mMockNetwork, mMockNetworkCapabilities); 185 186 assertThat(entry.getSummary()).isEqualTo(""); 187 } 188 189 @Test testGetSecurityTypes_connectedWifiNetwork_showsCurrentSecurityType()190 public void testGetSecurityTypes_connectedWifiNetwork_showsCurrentSecurityType() { 191 when(mMockWifiInfo.isPasspointAp()).thenReturn(true); 192 when(mMockWifiInfo.getPasspointFqdn()).thenReturn(FQDN); 193 when(mMockWifiInfo.getPasspointUniqueId()).thenReturn( 194 getPasspointConfiguration().getUniqueId()); 195 when(mMockWifiInfo.getCurrentSecurityType()) 196 .thenReturn(WifiInfo.SECURITY_TYPE_PASSPOINT_R1_R2); 197 198 PasspointWifiEntry entry = new PasspointWifiEntry(mMockInjector, mTestHandler, 199 getPasspointConfiguration(), mMockWifiManager, 200 false /* forSavedNetworksPage */); 201 202 assertThat(entry.getSecurityTypes()).containsExactlyElementsIn(Arrays.asList( 203 WifiInfo.SECURITY_TYPE_PASSPOINT_R1_R2, 204 WifiInfo.SECURITY_TYPE_PASSPOINT_R3)); 205 206 entry.onNetworkCapabilitiesChanged(mMockNetwork, mMockNetworkCapabilities); 207 208 assertThat(entry.getSecurityTypes()) 209 .containsExactly(WifiInfo.SECURITY_TYPE_PASSPOINT_R1_R2); 210 211 when(mMockWifiInfo.getCurrentSecurityType()) 212 .thenReturn(WifiInfo.SECURITY_TYPE_PASSPOINT_R3); 213 entry.onNetworkCapabilitiesChanged(mMockNetwork, mMockNetworkCapabilities); 214 215 assertThat(entry.getSecurityTypes()).containsExactly(WifiInfo.SECURITY_TYPE_PASSPOINT_R3); 216 } 217 218 @Test testGetSecurityString_showsPasspoint()219 public void testGetSecurityString_showsPasspoint() { 220 PasspointConfiguration passpointConfiguration = getPasspointConfiguration(); 221 String passpointSecurity = "Passpoint"; 222 when(mMockContext.getString(R.string.wifitrackerlib_wifi_security_passpoint)) 223 .thenReturn(passpointSecurity); 224 225 PasspointWifiEntry passpointWifiEntry = new PasspointWifiEntry(mMockInjector, 226 mTestHandler, passpointConfiguration, mMockWifiManager, 227 false /* forSavedNetworksPage */); 228 229 assertThat(passpointWifiEntry.getSecurityString(false)).isEqualTo(passpointSecurity); 230 } 231 232 @Test testShouldShowXLevelIcon_unvalidatedOrLowQuality_returnsTrue()233 public void testShouldShowXLevelIcon_unvalidatedOrLowQuality_returnsTrue() { 234 when(mMockWifiInfo.isPasspointAp()).thenReturn(true); 235 when(mMockWifiInfo.getPasspointFqdn()).thenReturn(FQDN); 236 when(mMockWifiInfo.getPasspointUniqueId()).thenReturn( 237 getPasspointConfiguration().getUniqueId()); 238 239 PasspointWifiEntry entry = new PasspointWifiEntry(mMockInjector, mTestHandler, 240 getPasspointConfiguration(), mMockWifiManager, 241 false /* forSavedNetworksPage */); 242 243 // Disconnected should return false; 244 assertThat(entry.shouldShowXLevelIcon()).isEqualTo(false); 245 246 // Connected but validation attempt not complete, should not show X level icon yet. 247 entry.onNetworkCapabilitiesChanged(mMockNetwork, mMockNetworkCapabilities); 248 assertThat(entry.shouldShowXLevelIcon()).isEqualTo(false); 249 250 // Validation attempt complete, should show X level icon. 251 ConnectivityDiagnosticsManager.ConnectivityReport connectivityReport = mock( 252 ConnectivityDiagnosticsManager.ConnectivityReport.class); 253 when(connectivityReport.getNetwork()).thenReturn(mMockNetwork); 254 entry.updateConnectivityReport(connectivityReport); 255 assertThat(entry.shouldShowXLevelIcon()).isEqualTo(true); 256 257 // Internet validated, should not show X level icon. 258 when(mMockNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) 259 .thenReturn(true); 260 entry.onNetworkCapabilitiesChanged(mMockNetwork, mMockNetworkCapabilities); 261 assertThat(entry.shouldShowXLevelIcon()).isEqualTo(false); 262 263 // Cell becomes default (i.e. low quality wifi), show X level icon. 264 entry.onDefaultNetworkCapabilitiesChanged(Mockito.mock(Network.class), 265 new NetworkCapabilities.Builder() 266 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).build()); 267 assertThat(entry.shouldShowXLevelIcon()).isEqualTo(true); 268 } 269 270 @Test testGetMacAddress_wifiInfoAvailable_usesWifiInfoMacAddress()271 public void testGetMacAddress_wifiInfoAvailable_usesWifiInfoMacAddress() { 272 final String factoryMac = "01:23:45:67:89:ab"; 273 final String wifiInfoMac = "11:23:45:67:89:ab"; 274 when(mMockWifiManager.getFactoryMacAddresses()).thenReturn(new String[]{factoryMac}); 275 when(mMockWifiInfo.isPasspointAp()).thenReturn(true); 276 when(mMockWifiInfo.getPasspointFqdn()).thenReturn(FQDN); 277 when(mMockWifiInfo.getMacAddress()).thenReturn(wifiInfoMac); 278 when(mMockWifiInfo.getPasspointUniqueId()).thenReturn( 279 getPasspointConfiguration().getUniqueId()); 280 PasspointWifiEntry entry = new PasspointWifiEntry(mMockInjector, mTestHandler, 281 getPasspointConfiguration(), mMockWifiManager, 282 false /* forSavedNetworksPage */); 283 284 entry.onNetworkCapabilitiesChanged(mMockNetwork, mMockNetworkCapabilities); 285 286 assertThat(entry.getMacAddress()).isEqualTo(wifiInfoMac); 287 } 288 289 @Test testIsAutoJoinEnabled_nullConfigs_returnsFalse()290 public void testIsAutoJoinEnabled_nullConfigs_returnsFalse() { 291 PasspointWifiEntry entry = new PasspointWifiEntry(mMockInjector, mTestHandler, 292 getPasspointConfiguration(), mMockWifiManager, 293 false /* forSavedNetworksPage */); 294 295 entry.updatePasspointConfig(null); 296 297 assertThat(entry.isAutoJoinEnabled()).isFalse(); 298 } 299 300 @Test testCanSignIn_captivePortalCapability_returnsTrue()301 public void testCanSignIn_captivePortalCapability_returnsTrue() { 302 PasspointWifiEntry entry = new PasspointWifiEntry(mMockInjector, mTestHandler, 303 getPasspointConfiguration(), mMockWifiManager, 304 false /* forSavedNetworksPage */); 305 306 when(mMockWifiInfo.isPasspointAp()).thenReturn(true); 307 when(mMockWifiInfo.getPasspointFqdn()).thenReturn(FQDN); 308 when(mMockWifiInfo.getPasspointUniqueId()).thenReturn( 309 getPasspointConfiguration().getUniqueId()); 310 when(mMockNetworkCapabilities.hasCapability( 311 NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL)).thenReturn(true); 312 entry.onNetworkCapabilitiesChanged(mMockNetwork, mMockNetworkCapabilities); 313 314 assertThat(entry.canSignIn()).isTrue(); 315 } 316 317 @Test testUpdateNetworkCapabilities_userConnect_autoOpenCaptivePortalOnce()318 public void testUpdateNetworkCapabilities_userConnect_autoOpenCaptivePortalOnce() { 319 PasspointWifiEntry entry = new PasspointWifiEntry(mMockInjector, mTestHandler, 320 getPasspointConfiguration(), mMockWifiManager, 321 false /* forSavedNetworksPage */); 322 323 MockitoSession session = mockitoSession().spyStatic(NonSdkApiWrapper.class).startMocking(); 324 try { 325 // Simulate user tapping on the network and receiving captive portal capabilities. 326 // This should trigger the captive portal app. 327 entry.connect(null /* callback */); 328 when(mMockWifiInfo.isPasspointAp()).thenReturn(true); 329 when(mMockWifiInfo.getPasspointFqdn()).thenReturn(FQDN); 330 when(mMockWifiInfo.getPasspointUniqueId()).thenReturn( 331 getPasspointConfiguration().getUniqueId()); 332 when(mMockNetworkCapabilities.hasCapability( 333 NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL)).thenReturn(true); 334 entry.onNetworkCapabilitiesChanged(mMockNetwork, mMockNetworkCapabilities); 335 336 verify(() -> NonSdkApiWrapper.startCaptivePortalApp(any(), any()), times(1)); 337 338 // Update network capabilities again. This should not trigger the captive portal app. 339 entry.onNetworkCapabilitiesChanged(mMockNetwork, mMockNetworkCapabilities); 340 341 verify(() -> NonSdkApiWrapper.startCaptivePortalApp(any(), any()), times(1)); 342 } finally { 343 session.finishMocking(); 344 } 345 346 } 347 348 @Test testDisconnect_noScansOrWifiConfig_disconnectIsSuccessful()349 public void testDisconnect_noScansOrWifiConfig_disconnectIsSuccessful() { 350 // Setup a connected PasspointWifiEntry 351 String summarySeparator = " / "; 352 String[] wifiStatusArray = new String[]{"", "Scanning", "Connecting", 353 "Authenticating", "Obtaining IP address", "Connected"}; 354 when(mMockContext.getString(R.string.wifitrackerlib_summary_separator)) 355 .thenReturn(summarySeparator); 356 when(mMockResources.getStringArray(R.array.wifitrackerlib_wifi_status)) 357 .thenReturn(wifiStatusArray); 358 when(mMockWifiInfo.isPasspointAp()).thenReturn(true); 359 when(mMockWifiInfo.getPasspointFqdn()).thenReturn(FQDN); 360 when(mMockWifiInfo.getPasspointUniqueId()).thenReturn( 361 getPasspointConfiguration().getUniqueId()); 362 when(mMockNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) 363 .thenReturn(true); 364 PasspointWifiEntry entry = new PasspointWifiEntry(mMockInjector, mTestHandler, 365 getPasspointConfiguration(), mMockWifiManager, 366 false /* forSavedNetworksPage */); 367 entry.onNetworkCapabilitiesChanged(mMockNetwork, mMockNetworkCapabilities); 368 369 // Disconnect the entry before it can be updated with scans and a WifiConfiguration 370 entry.disconnect(null); 371 372 verify(mMockWifiManager).disableEphemeralNetwork(FQDN); 373 verify(mMockWifiManager).disconnect(); 374 } 375 } 376