1 /* 2 * Copyright (C) 2017 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 package com.android.settings.wifi.details; 17 18 import static com.google.common.truth.Truth.assertThat; 19 import static org.mockito.ArgumentMatchers.anyInt; 20 import static org.mockito.ArgumentMatchers.anyString; 21 import static org.mockito.ArgumentMatchers.nullable; 22 import static org.mockito.Matchers.any; 23 import static org.mockito.Mockito.doNothing; 24 import static org.mockito.Mockito.inOrder; 25 import static org.mockito.Mockito.never; 26 import static org.mockito.Mockito.reset; 27 import static org.mockito.Mockito.spy; 28 import static org.mockito.Mockito.times; 29 import static org.mockito.Mockito.verify; 30 import static org.mockito.Mockito.when; 31 32 import android.app.Activity; 33 import android.arch.lifecycle.LifecycleOwner; 34 import android.content.ComponentName; 35 import android.content.Context; 36 import android.content.Intent; 37 import android.graphics.drawable.ColorDrawable; 38 import android.graphics.drawable.Drawable; 39 import android.net.ConnectivityManager; 40 import android.net.ConnectivityManager.NetworkCallback; 41 import android.net.IpPrefix; 42 import android.net.LinkAddress; 43 import android.net.LinkProperties; 44 import android.net.Network; 45 import android.net.NetworkCapabilities; 46 import android.net.NetworkInfo; 47 import android.net.NetworkRequest; 48 import android.net.RouteInfo; 49 import android.net.wifi.WifiConfiguration; 50 import android.net.wifi.WifiInfo; 51 import android.net.wifi.WifiManager; 52 import android.os.Handler; 53 import android.provider.Settings; 54 import android.support.v7.preference.PreferenceCategory; 55 import android.support.v7.preference.PreferenceScreen; 56 import android.view.View; 57 import android.view.View.OnClickListener; 58 import android.widget.ImageView; 59 60 import com.android.internal.logging.nano.MetricsProto; 61 import com.android.settings.R; 62 import com.android.settings.applications.LayoutPreference; 63 import com.android.settings.testutils.SettingsRobolectricTestRunner; 64 import com.android.settings.testutils.shadow.ShadowBidiFormatter; 65 import com.android.settings.testutils.shadow.ShadowDevicePolicyManager; 66 import com.android.settings.testutils.shadow.ShadowEntityHeaderController; 67 import com.android.settings.testutils.shadow.ShadowPackageManagerWrapper; 68 import com.android.settings.widget.ActionButtonPreference; 69 import com.android.settings.widget.ActionButtonPreferenceTest; 70 import com.android.settings.widget.EntityHeaderController; 71 import com.android.settings.wifi.WifiDetailPreference; 72 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 73 import com.android.settingslib.core.lifecycle.Lifecycle; 74 import com.android.settingslib.wifi.AccessPoint; 75 76 import org.junit.Before; 77 import org.junit.Test; 78 import org.junit.runner.RunWith; 79 import org.mockito.Answers; 80 import org.mockito.ArgumentCaptor; 81 import org.mockito.Captor; 82 import org.mockito.InOrder; 83 import org.mockito.Mock; 84 import org.mockito.MockitoAnnotations; 85 import org.robolectric.RuntimeEnvironment; 86 import org.robolectric.annotation.Config; 87 88 import java.net.Inet4Address; 89 import java.net.InetAddress; 90 import java.net.UnknownHostException; 91 import java.util.Arrays; 92 import java.util.stream.Collectors; 93 94 @RunWith(SettingsRobolectricTestRunner.class) 95 @Config(shadows = { 96 ShadowDevicePolicyManager.class, 97 ShadowEntityHeaderController.class, 98 ShadowPackageManagerWrapper.class, 99 ShadowBidiFormatter.class 100 }) 101 public class WifiDetailPreferenceControllerTest { 102 103 private static final int LEVEL = 1; 104 private static final int RSSI = -55; 105 private static final int LINK_SPEED = 123; 106 private static final String MAC_ADDRESS = WifiInfo.DEFAULT_MAC_ADDRESS; 107 private static final String SECURITY = "None"; 108 109 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 110 private PreferenceScreen mockScreen; 111 112 @Mock 113 private AccessPoint mockAccessPoint; 114 @Mock 115 private Activity mockActivity; 116 @Mock 117 private ConnectivityManager mockConnectivityManager; 118 @Mock 119 private Network mockNetwork; 120 @Mock 121 private NetworkInfo mockNetworkInfo; 122 @Mock 123 private WifiConfiguration mockWifiConfig; 124 @Mock 125 private WifiInfo mockWifiInfo; 126 @Mock 127 private WifiNetworkDetailsFragment mockFragment; 128 @Mock 129 private WifiManager mockWifiManager; 130 @Mock 131 private MetricsFeatureProvider mockMetricsFeatureProvider; 132 @Mock 133 private WifiDetailPreferenceController.IconInjector mockIconInjector; 134 135 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 136 private EntityHeaderController mockHeaderController; 137 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 138 private LayoutPreference mockHeaderLayoutPreference; 139 @Mock 140 private ImageView mockHeaderIcon; 141 142 @Mock 143 private ActionButtonPreference mockButtonsPref; 144 @Mock 145 private WifiDetailPreference mockSignalStrengthPref; 146 @Mock 147 private WifiDetailPreference mockLinkSpeedPref; 148 @Mock 149 private WifiDetailPreference mockFrequencyPref; 150 @Mock 151 private WifiDetailPreference mockSecurityPref; 152 @Mock 153 private WifiDetailPreference mockMacAddressPref; 154 @Mock 155 private WifiDetailPreference mockIpAddressPref; 156 @Mock 157 private WifiDetailPreference mockGatewayPref; 158 @Mock 159 private WifiDetailPreference mockSubnetPref; 160 @Mock 161 private WifiDetailPreference mockDnsPref; 162 @Mock 163 private PreferenceCategory mockIpv6Category; 164 @Mock 165 private WifiDetailPreference mockIpv6AddressesPref; 166 167 @Captor 168 private ArgumentCaptor<NetworkCallback> mCallbackCaptor; 169 @Captor 170 private ArgumentCaptor<View.OnClickListener> mForgetClickListener; 171 172 private Context mContext; 173 private Lifecycle mLifecycle; 174 private LifecycleOwner mLifecycleOwner; 175 private LinkProperties mLinkProperties; 176 private WifiDetailPreferenceController mController; 177 178 // This class exists so that these values can be made static final. They can't be static final 179 // members of the test class, because any attempt to call IpPrefix or RouteInfo constructors 180 // during static initialization of the test class results in NoSuchMethorError being thrown 181 // when the test is run. 182 private static class Constants { 183 static final int IPV4_PREFIXLEN = 25; 184 static final LinkAddress IPV4_ADDR; 185 static final Inet4Address IPV4_GATEWAY; 186 static final RouteInfo IPV4_DEFAULT; 187 static final RouteInfo IPV4_SUBNET; 188 static final LinkAddress IPV6_LINKLOCAL; 189 static final LinkAddress IPV6_GLOBAL1; 190 static final LinkAddress IPV6_GLOBAL2; 191 static final InetAddress IPV4_DNS1; 192 static final InetAddress IPV4_DNS2; 193 static final InetAddress IPV6_DNS; 194 195 private static LinkAddress ipv6LinkAddress(String addr) throws UnknownHostException { 196 return new LinkAddress(InetAddress.getByName(addr), 64); 197 } 198 199 private static LinkAddress ipv4LinkAddress(String addr, int prefixlen) 200 throws UnknownHostException { 201 return new LinkAddress(InetAddress.getByName(addr), prefixlen); 202 } 203 204 static { 205 try { 206 // We create our test constants in these roundabout ways because the robolectric 207 // shadows don't contain NetworkUtils.parseNumericAddress and other utility methods, 208 // so the easy ways to do things fail with NoSuchMethodError. 209 IPV4_ADDR = ipv4LinkAddress("192.0.2.2", IPV4_PREFIXLEN); 210 IPV4_GATEWAY = (Inet4Address) InetAddress.getByName("192.0.2.127"); 211 212 final Inet4Address any4 = (Inet4Address) InetAddress.getByName("0.0.0.0"); 213 IpPrefix subnet = new IpPrefix(IPV4_ADDR.getAddress(), IPV4_PREFIXLEN); 214 IPV4_SUBNET = new RouteInfo(subnet, any4); 215 IPV4_DEFAULT = new RouteInfo(new IpPrefix(any4, 0), IPV4_GATEWAY); 216 217 IPV6_LINKLOCAL = ipv6LinkAddress("fe80::211:25ff:fef8:7cb2%1"); 218 IPV6_GLOBAL1 = ipv6LinkAddress("2001:db8:1::211:25ff:fef8:7cb2"); 219 IPV6_GLOBAL2 = ipv6LinkAddress("2001:db8:1::3dfe:8902:f98f:739d"); 220 221 IPV4_DNS1 = InetAddress.getByName("8.8.8.8"); 222 IPV4_DNS2 = InetAddress.getByName("8.8.4.4"); 223 IPV6_DNS = InetAddress.getByName("2001:4860:4860::64"); 224 } catch (UnknownHostException e) { 225 throw new RuntimeException("Invalid hardcoded IP addresss: " + e); 226 } 227 } 228 } 229 230 @Before 231 public void setUp() { 232 MockitoAnnotations.initMocks(this); 233 234 mContext = spy(RuntimeEnvironment.application); 235 mLifecycleOwner = () -> mLifecycle; 236 mLifecycle = new Lifecycle(mLifecycleOwner); 237 238 when(mockAccessPoint.getConfig()).thenReturn(mockWifiConfig); 239 when(mockAccessPoint.getLevel()).thenReturn(LEVEL); 240 when(mockAccessPoint.getSecurityString(false)).thenReturn(SECURITY); 241 when(mockConnectivityManager.getNetworkInfo(any(Network.class))) 242 .thenReturn(mockNetworkInfo); 243 doNothing().when(mockConnectivityManager).registerNetworkCallback( 244 nullable(NetworkRequest.class), mCallbackCaptor.capture(), nullable(Handler.class)); 245 mockButtonsPref = ActionButtonPreferenceTest.createMock(); 246 when(mockButtonsPref.setButton1OnClickListener(mForgetClickListener.capture())) 247 .thenReturn(mockButtonsPref); 248 249 when(mockWifiInfo.getLinkSpeed()).thenReturn(LINK_SPEED); 250 when(mockWifiInfo.getRssi()).thenReturn(RSSI); 251 when(mockWifiInfo.getMacAddress()).thenReturn(MAC_ADDRESS); 252 when(mockWifiManager.getConnectionInfo()).thenReturn(mockWifiInfo); 253 254 when(mockWifiManager.getCurrentNetwork()).thenReturn(mockNetwork); 255 mLinkProperties = new LinkProperties(); 256 when(mockConnectivityManager.getLinkProperties(mockNetwork)).thenReturn(mLinkProperties); 257 258 when(mockFragment.getActivity()).thenReturn(mockActivity); 259 260 ShadowEntityHeaderController.setUseMock(mockHeaderController); 261 // builder pattern 262 when(mockHeaderController.setRecyclerView(mockFragment.getListView(), mLifecycle)) 263 .thenReturn(mockHeaderController); 264 when(mockHeaderController.setSummary(anyString())).thenReturn(mockHeaderController); 265 when(mockIconInjector.getIcon(anyInt())).thenReturn(new ColorDrawable()); 266 267 setupMockedPreferenceScreen(); 268 mController = newWifiDetailPreferenceController(); 269 } 270 271 private WifiDetailPreferenceController newWifiDetailPreferenceController() { 272 return new WifiDetailPreferenceController( 273 mockAccessPoint, 274 mockConnectivityManager, 275 mContext, 276 mockFragment, 277 null, // Handler 278 mLifecycle, 279 mockWifiManager, 280 mockMetricsFeatureProvider, 281 mockIconInjector); 282 } 283 284 private void setupMockedPreferenceScreen() { 285 when(mockScreen.getPreferenceManager().getContext()).thenReturn(mContext); 286 287 when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_HEADER)) 288 .thenReturn(mockHeaderLayoutPreference); 289 when(mockHeaderLayoutPreference.findViewById(R.id.entity_header_icon)) 290 .thenReturn(mockHeaderIcon); 291 292 when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_BUTTONS_PREF)) 293 .thenReturn(mockButtonsPref); 294 when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_SIGNAL_STRENGTH_PREF)) 295 .thenReturn(mockSignalStrengthPref); 296 when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_LINK_SPEED)) 297 .thenReturn(mockLinkSpeedPref); 298 when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_FREQUENCY_PREF)) 299 .thenReturn(mockFrequencyPref); 300 when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_SECURITY_PREF)) 301 .thenReturn(mockSecurityPref); 302 when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_MAC_ADDRESS_PREF)) 303 .thenReturn(mockMacAddressPref); 304 when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_IP_ADDRESS_PREF)) 305 .thenReturn(mockIpAddressPref); 306 when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_GATEWAY_PREF)) 307 .thenReturn(mockGatewayPref); 308 when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_SUBNET_MASK_PREF)) 309 .thenReturn(mockSubnetPref); 310 when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_DNS_PREF)) 311 .thenReturn(mockDnsPref); 312 when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_IPV6_CATEGORY)) 313 .thenReturn(mockIpv6Category); 314 when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_IPV6_ADDRESSES_PREF)) 315 .thenReturn(mockIpv6AddressesPref); 316 } 317 318 private void displayAndResume() { 319 mController.displayPreference(mockScreen); 320 mController.onResume(); 321 } 322 323 @Test 324 public void isAvailable_shouldAlwaysReturnTrue() { 325 mController.displayPreference(mockScreen); 326 327 assertThat(mController.isAvailable()).isTrue(); 328 } 329 330 @Test 331 public void securityPreference_stringShouldBeSet() { 332 displayAndResume(); 333 334 verify(mockSecurityPref).setDetailText(SECURITY); 335 } 336 337 @Test 338 public void latestWifiInfo_shouldBeFetchedInDisplayPreference() { 339 displayAndResume(); 340 341 verify(mockWifiManager, times(1)).getConnectionInfo(); 342 } 343 344 @Test 345 public void latestNetworkInfo_shouldBeFetchedInDisplayPreference() { 346 displayAndResume(); 347 348 verify(mockConnectivityManager, times(1)).getNetworkInfo(any(Network.class)); 349 } 350 351 @Test 352 public void networkCallback_shouldBeRegisteredOnResume() { 353 displayAndResume(); 354 355 verify(mockConnectivityManager, times(1)).registerNetworkCallback( 356 nullable(NetworkRequest.class), mCallbackCaptor.capture(), nullable(Handler.class)); 357 } 358 359 @Test 360 public void networkCallback_shouldBeUnregisteredOnPause() { 361 displayAndResume(); 362 mController.onPause(); 363 364 verify(mockConnectivityManager, times(1)) 365 .unregisterNetworkCallback(mCallbackCaptor.getValue()); 366 } 367 368 @Test 369 public void entityHeader_shouldHaveIconSet() { 370 Drawable expectedIcon = mockIconInjector.getIcon(LEVEL); 371 372 displayAndResume(); 373 374 verify(mockHeaderController).setIcon(expectedIcon); 375 } 376 377 @Test 378 public void entityHeader_shouldHaveLabelSetToSsid() { 379 String label = "ssid"; 380 when(mockAccessPoint.getSsidStr()).thenReturn(label); 381 382 displayAndResume(); 383 384 verify(mockHeaderController).setLabel(label); 385 } 386 387 @Test 388 public void entityHeader_shouldHaveSummarySet() { 389 String summary = "summary"; 390 when(mockAccessPoint.getSettingsSummary()).thenReturn(summary); 391 392 displayAndResume(); 393 394 verify(mockHeaderController).setSummary(summary); 395 } 396 397 @Test 398 public void signalStrengthPref_shouldHaveIconSet() { 399 displayAndResume(); 400 401 verify(mockSignalStrengthPref).setIcon(any(Drawable.class)); 402 } 403 404 @Test 405 public void signalStrengthPref_shouldHaveDetailTextSet() { 406 String expectedStrength = 407 mContext.getResources().getStringArray(R.array.wifi_signal)[LEVEL]; 408 409 displayAndResume(); 410 411 verify(mockSignalStrengthPref).setDetailText(expectedStrength); 412 } 413 414 @Test 415 public void linkSpeedPref_shouldHaveDetailTextSet() { 416 String expectedLinkSpeed = mContext.getString(R.string.link_speed, LINK_SPEED); 417 418 displayAndResume(); 419 420 verify(mockLinkSpeedPref).setDetailText(expectedLinkSpeed); 421 } 422 423 @Test 424 public void linkSpeedPref_shouldNotShowIfNotSet() { 425 when(mockWifiInfo.getLinkSpeed()).thenReturn(-1); 426 427 displayAndResume(); 428 429 verify(mockLinkSpeedPref).setVisible(false); 430 } 431 432 @Test 433 public void macAddressPref_shouldHaveDetailTextSet() { 434 displayAndResume(); 435 436 verify(mockMacAddressPref).setDetailText(MAC_ADDRESS); 437 } 438 439 @Test 440 public void ipAddressPref_shouldHaveDetailTextSet() { 441 mLinkProperties.addLinkAddress(Constants.IPV4_ADDR); 442 443 displayAndResume(); 444 445 verify(mockIpAddressPref).setDetailText(Constants.IPV4_ADDR.getAddress().getHostAddress()); 446 } 447 448 @Test 449 public void gatewayAndSubnet_shouldHaveDetailTextSet() { 450 mLinkProperties.addLinkAddress(Constants.IPV4_ADDR); 451 mLinkProperties.addRoute(Constants.IPV4_DEFAULT); 452 mLinkProperties.addRoute(Constants.IPV4_SUBNET); 453 454 displayAndResume(); 455 456 verify(mockSubnetPref).setDetailText("255.255.255.128"); 457 verify(mockGatewayPref).setDetailText("192.0.2.127"); 458 } 459 460 @Test 461 public void dnsServersPref_shouldHaveDetailTextSet() throws UnknownHostException { 462 mLinkProperties.addDnsServer(InetAddress.getByAddress(new byte[] {8, 8, 4, 4})); 463 mLinkProperties.addDnsServer(InetAddress.getByAddress(new byte[] {8, 8, 8, 8})); 464 mLinkProperties.addDnsServer(Constants.IPV6_DNS); 465 466 displayAndResume(); 467 468 verify(mockDnsPref).setDetailText( 469 "8.8.4.4\n" + 470 "8.8.8.8\n" + 471 Constants.IPV6_DNS.getHostAddress()); 472 } 473 474 @Test 475 public void noCurrentNetwork_shouldFinishActivity() { 476 // If WifiManager#getCurrentNetwork() returns null, then the network is neither connected 477 // nor connecting and WifiStateMachine has not reached L2ConnectedState. 478 when(mockWifiManager.getCurrentNetwork()).thenReturn(null); 479 480 displayAndResume(); 481 482 verify(mockActivity).finish(); 483 } 484 485 @Test 486 public void noLinkProperties_allIpDetailsHidden() { 487 when(mockConnectivityManager.getLinkProperties(mockNetwork)).thenReturn(null); 488 reset(mockIpv6Category, mockIpAddressPref, mockSubnetPref, mockGatewayPref, mockDnsPref); 489 490 displayAndResume(); 491 492 verify(mockIpv6Category).setVisible(false); 493 verify(mockIpAddressPref).setVisible(false); 494 verify(mockSubnetPref).setVisible(false); 495 verify(mockGatewayPref).setVisible(false); 496 verify(mockDnsPref).setVisible(false); 497 verify(mockIpv6Category, never()).setVisible(true); 498 verify(mockIpAddressPref, never()).setVisible(true); 499 verify(mockSubnetPref, never()).setVisible(true); 500 verify(mockGatewayPref, never()).setVisible(true); 501 verify(mockDnsPref, never()).setVisible(true); 502 } 503 504 // Convenience method to convert a LinkAddress to a string without a prefix length. 505 private String asString(LinkAddress l) { 506 return l.getAddress().getHostAddress(); 507 } 508 509 // Pretend that the NetworkCallback was triggered with a new copy of lp. We need to create a 510 // new copy because the code only updates if !mLinkProperties.equals(lp). 511 private void updateLinkProperties(LinkProperties lp) { 512 mCallbackCaptor.getValue().onLinkPropertiesChanged(mockNetwork, new LinkProperties(lp)); 513 } 514 515 private void updateNetworkCapabilities(NetworkCapabilities nc) { 516 mCallbackCaptor.getValue().onCapabilitiesChanged(mockNetwork, new NetworkCapabilities(nc)); 517 } 518 519 private NetworkCapabilities makeNetworkCapabilities() { 520 NetworkCapabilities nc = new NetworkCapabilities(); 521 nc.clearAll(); 522 nc.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); 523 return nc; 524 } 525 526 private void verifyDisplayedIpv6Addresses(InOrder inOrder, LinkAddress... addresses) { 527 String text = Arrays.stream(addresses) 528 .map(address -> asString(address)) 529 .collect(Collectors.joining("\n")); 530 inOrder.verify(mockIpv6AddressesPref).setSummary(text); 531 } 532 533 @Test 534 public void onLinkPropertiesChanged_updatesFields() { 535 displayAndResume(); 536 537 InOrder inOrder = inOrder(mockIpAddressPref, mockGatewayPref, mockSubnetPref, 538 mockDnsPref, mockIpv6Category, mockIpv6AddressesPref); 539 540 LinkProperties lp = new LinkProperties(); 541 542 lp.addLinkAddress(Constants.IPV6_LINKLOCAL); 543 updateLinkProperties(lp); 544 verifyDisplayedIpv6Addresses(inOrder, Constants.IPV6_LINKLOCAL); 545 inOrder.verify(mockIpv6Category).setVisible(true); 546 547 lp.addRoute(Constants.IPV4_DEFAULT); 548 updateLinkProperties(lp); 549 inOrder.verify(mockGatewayPref).setDetailText(Constants.IPV4_GATEWAY.getHostAddress()); 550 inOrder.verify(mockGatewayPref).setVisible(true); 551 552 lp.addLinkAddress(Constants.IPV4_ADDR); 553 lp.addRoute(Constants.IPV4_SUBNET); 554 updateLinkProperties(lp); 555 inOrder.verify(mockIpAddressPref).setDetailText(asString(Constants.IPV4_ADDR)); 556 inOrder.verify(mockIpAddressPref).setVisible(true); 557 inOrder.verify(mockSubnetPref).setDetailText("255.255.255.128"); 558 inOrder.verify(mockSubnetPref).setVisible(true); 559 560 lp.addLinkAddress(Constants.IPV6_GLOBAL1); 561 lp.addLinkAddress(Constants.IPV6_GLOBAL2); 562 updateLinkProperties(lp); 563 verifyDisplayedIpv6Addresses(inOrder, 564 Constants.IPV6_LINKLOCAL, 565 Constants.IPV6_GLOBAL1, 566 Constants.IPV6_GLOBAL2); 567 568 lp.removeLinkAddress(Constants.IPV6_GLOBAL1); 569 updateLinkProperties(lp); 570 verifyDisplayedIpv6Addresses(inOrder, 571 Constants.IPV6_LINKLOCAL, 572 Constants.IPV6_GLOBAL2); 573 574 lp.addDnsServer(Constants.IPV6_DNS); 575 updateLinkProperties(lp); 576 inOrder.verify(mockDnsPref).setDetailText(Constants.IPV6_DNS.getHostAddress()); 577 inOrder.verify(mockDnsPref).setVisible(true); 578 579 lp.addDnsServer(Constants.IPV4_DNS1); 580 lp.addDnsServer(Constants.IPV4_DNS2); 581 updateLinkProperties(lp); 582 inOrder.verify(mockDnsPref).setDetailText( 583 Constants.IPV6_DNS.getHostAddress() + "\n" + 584 Constants.IPV4_DNS1.getHostAddress() + "\n" + 585 Constants.IPV4_DNS2.getHostAddress()); 586 inOrder.verify(mockDnsPref).setVisible(true); 587 } 588 589 @Test 590 public void onCapabilitiesChanged_callsRefreshIfNecessary() { 591 NetworkCapabilities nc = makeNetworkCapabilities(); 592 when(mockConnectivityManager.getNetworkCapabilities(mockNetwork)) 593 .thenReturn(new NetworkCapabilities(nc)); 594 595 String summary = "Connected, no Internet"; 596 when(mockAccessPoint.getSettingsSummary()).thenReturn(summary); 597 598 InOrder inOrder = inOrder(mockHeaderController); 599 displayAndResume(); 600 inOrder.verify(mockHeaderController).setSummary(summary); 601 602 // Check that an irrelevant capability update does not update the access point summary, as 603 // doing so could cause unnecessary jank... 604 summary = "Connected"; 605 when(mockAccessPoint.getSettingsSummary()).thenReturn(summary); 606 updateNetworkCapabilities(nc); 607 inOrder.verify(mockHeaderController, never()).setSummary(any(CharSequence.class)); 608 609 // ... but that if the network validates, then we do refresh. 610 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); 611 updateNetworkCapabilities(nc); 612 inOrder.verify(mockHeaderController).setSummary(summary); 613 614 summary = "Connected, no Internet"; 615 when(mockAccessPoint.getSettingsSummary()).thenReturn(summary); 616 617 // Another irrelevant update won't cause the UI to refresh... 618 updateNetworkCapabilities(nc); 619 inOrder.verify(mockHeaderController, never()).setSummary(any(CharSequence.class)); 620 621 // ... but if the network is no longer validated, then we display "connected, no Internet". 622 nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); 623 updateNetworkCapabilities(nc); 624 inOrder.verify(mockHeaderController).setSummary(summary); 625 } 626 627 @Test 628 public void canForgetNetwork_noNetwork() { 629 when(mockAccessPoint.getConfig()).thenReturn(null); 630 631 mController = newWifiDetailPreferenceController(); 632 displayAndResume(); 633 634 verify(mockButtonsPref).setButton1Visible(false); 635 } 636 637 @Test 638 public void canForgetNetwork_ephemeral() { 639 when(mockWifiInfo.isEphemeral()).thenReturn(true); 640 when(mockAccessPoint.getConfig()).thenReturn(null); 641 642 displayAndResume(); 643 644 verify(mockButtonsPref).setButton1Visible(true); 645 } 646 647 @Test 648 public void canForgetNetwork_saved() { 649 displayAndResume(); 650 651 verify(mockButtonsPref).setButton1Visible(true); 652 } 653 654 @Test 655 public void canForgetNetwork_lockedDown() { 656 lockDownNetwork(); 657 658 displayAndResume(); 659 660 verify(mockButtonsPref).setButton1Visible(false); 661 } 662 663 @Test 664 public void canModifyNetwork_saved() { 665 assertThat(mController.canModifyNetwork()).isTrue(); 666 } 667 668 @Test 669 public void canModifyNetwork_lockedDown() { 670 lockDownNetwork(); 671 672 assertThat(mController.canModifyNetwork()).isFalse(); 673 } 674 675 /** 676 * Pretends that current network is locked down by device owner. 677 */ 678 private void lockDownNetwork() { 679 final int doUserId = 123; 680 final int doUid = 1234; 681 String doPackage = "some.package"; 682 683 mockWifiConfig.creatorUid = doUid; 684 ComponentName doComponent = new ComponentName(doPackage, "some.Class"); 685 ShadowPackageManagerWrapper.setPackageUidAsUser(doPackage, doUserId, doUid); 686 ShadowDevicePolicyManager.getShadow().setDeviceOwnerComponentOnAnyUser(doComponent); 687 ShadowDevicePolicyManager.getShadow().setDeviceOwnerUserId(doUserId); 688 689 Settings.Global.putInt(mContext.getContentResolver(), 690 Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 1); 691 } 692 693 @Test 694 public void forgetNetwork_ephemeral() { 695 String ssid = "ssid"; 696 when(mockWifiInfo.isEphemeral()).thenReturn(true); 697 when(mockWifiInfo.getSSID()).thenReturn(ssid); 698 699 displayAndResume(); 700 mForgetClickListener.getValue().onClick(null); 701 702 verify(mockWifiManager).disableEphemeralNetwork(ssid); 703 verify(mockMetricsFeatureProvider) 704 .action(mockActivity, MetricsProto.MetricsEvent.ACTION_WIFI_FORGET); 705 } 706 707 @Test 708 public void forgetNetwork_saved() { 709 mockWifiConfig.networkId = 5; 710 711 mController.displayPreference(mockScreen); 712 mForgetClickListener.getValue().onClick(null); 713 714 verify(mockWifiManager).forget(mockWifiConfig.networkId, null); 715 verify(mockMetricsFeatureProvider) 716 .action(mockActivity, MetricsProto.MetricsEvent.ACTION_WIFI_FORGET); 717 } 718 719 @Test 720 public void networkStateChangedIntent_shouldRefetchInfo() { 721 displayAndResume(); 722 723 verify(mockConnectivityManager, times(1)).getNetworkInfo(any(Network.class)); 724 verify(mockWifiManager, times(1)).getConnectionInfo(); 725 726 mContext.sendBroadcast(new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION)); 727 728 verify(mockConnectivityManager, times(2)).getNetworkInfo(any(Network.class)); 729 verify(mockWifiManager, times(2)).getConnectionInfo(); 730 } 731 732 @Test 733 public void rssiChangedIntent_shouldRefetchInfo() { 734 displayAndResume(); 735 736 verify(mockConnectivityManager, times(1)).getNetworkInfo(any(Network.class)); 737 verify(mockWifiManager, times(1)).getConnectionInfo(); 738 739 mContext.sendBroadcast(new Intent(WifiManager.RSSI_CHANGED_ACTION)); 740 741 verify(mockConnectivityManager, times(2)).getNetworkInfo(any(Network.class)); 742 verify(mockWifiManager, times(2)).getConnectionInfo(); 743 } 744 745 @Test 746 public void networkDisconnectedState_shouldFinishActivity() { 747 displayAndResume(); 748 749 when(mockConnectivityManager.getNetworkInfo(any(Network.class))).thenReturn(null); 750 mContext.sendBroadcast(new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION)); 751 752 verify(mockActivity).finish(); 753 } 754 755 @Test 756 public void networkOnLost_shouldFinishActivity() { 757 displayAndResume(); 758 759 mCallbackCaptor.getValue().onLost(mockNetwork); 760 761 verify(mockActivity).finish(); 762 } 763 764 @Test 765 public void ipv6AddressPref_shouldHaveHostAddressTextSet() { 766 mLinkProperties.addLinkAddress(Constants.IPV6_LINKLOCAL); 767 mLinkProperties.addLinkAddress(Constants.IPV6_GLOBAL1); 768 mLinkProperties.addLinkAddress(Constants.IPV6_GLOBAL2); 769 770 displayAndResume(); 771 772 String expectedAddresses = String.join("\n", 773 asString(Constants.IPV6_LINKLOCAL), 774 asString(Constants.IPV6_GLOBAL1), 775 asString(Constants.IPV6_GLOBAL2)); 776 777 verify(mockIpv6AddressesPref).setSummary(expectedAddresses); 778 } 779 780 @Test 781 public void ipv6AddressPref_shouldNotBeSelectable() { 782 mLinkProperties.addLinkAddress(Constants.IPV6_GLOBAL2); 783 784 displayAndResume(); 785 786 assertThat(mockIpv6AddressesPref.isSelectable()).isFalse(); 787 } 788 789 @Test 790 public void captivePortal_shouldShowSignInButton() { 791 InOrder inOrder = inOrder(mockButtonsPref); 792 793 displayAndResume(); 794 795 inOrder.verify(mockButtonsPref).setButton2Visible(false); 796 797 NetworkCapabilities nc = makeNetworkCapabilities(); 798 updateNetworkCapabilities(nc); 799 inOrder.verify(mockButtonsPref).setButton2Visible(false); 800 801 nc.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL); 802 updateNetworkCapabilities(nc); 803 inOrder.verify(mockButtonsPref).setButton2Visible(true); 804 805 nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL); 806 updateNetworkCapabilities(nc); 807 inOrder.verify(mockButtonsPref).setButton2Visible(false); 808 } 809 810 @Test 811 public void testSignInButton_shouldStartCaptivePortalApp() { 812 displayAndResume(); 813 814 ArgumentCaptor<OnClickListener> captor = ArgumentCaptor.forClass(OnClickListener.class); 815 verify(mockButtonsPref).setButton2OnClickListener(captor.capture()); 816 captor.getValue().onClick(null); 817 verify(mockConnectivityManager).startCaptivePortalApp(mockNetwork); 818 verify(mockMetricsFeatureProvider) 819 .action(mockActivity, MetricsProto.MetricsEvent.ACTION_WIFI_SIGNIN); 820 } 821 822 @Test 823 public void testRefreshRssiViews_shouldNotUpdateIfLevelIsSame() { 824 displayAndResume(); 825 826 mContext.sendBroadcast(new Intent(WifiManager.RSSI_CHANGED_ACTION)); 827 828 verify(mockAccessPoint, times(2)).getLevel(); 829 verify(mockIconInjector, times(1)).getIcon(anyInt()); 830 } 831 832 @Test 833 public void testRefreshRssiViews_shouldUpdateOnLevelChange() { 834 displayAndResume(); 835 836 when(mockAccessPoint.getLevel()).thenReturn(0); 837 mContext.sendBroadcast(new Intent(WifiManager.RSSI_CHANGED_ACTION)); 838 839 verify(mockAccessPoint, times(2)).getLevel(); 840 verify(mockIconInjector, times(2)).getIcon(anyInt()); 841 } 842 } 843