• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ipv6LinkAddress(String addr)195         private static LinkAddress ipv6LinkAddress(String addr) throws UnknownHostException {
196             return new LinkAddress(InetAddress.getByName(addr), 64);
197         }
198 
ipv4LinkAddress(String addr, int prefixlen)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
setUp()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 
newWifiDetailPreferenceController()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 
setupMockedPreferenceScreen()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 
displayAndResume()318     private void displayAndResume() {
319         mController.displayPreference(mockScreen);
320         mController.onResume();
321     }
322 
323     @Test
isAvailable_shouldAlwaysReturnTrue()324     public void isAvailable_shouldAlwaysReturnTrue() {
325         mController.displayPreference(mockScreen);
326 
327         assertThat(mController.isAvailable()).isTrue();
328     }
329 
330     @Test
securityPreference_stringShouldBeSet()331     public void securityPreference_stringShouldBeSet() {
332         displayAndResume();
333 
334         verify(mockSecurityPref).setDetailText(SECURITY);
335     }
336 
337     @Test
latestWifiInfo_shouldBeFetchedInDisplayPreference()338     public void latestWifiInfo_shouldBeFetchedInDisplayPreference() {
339         displayAndResume();
340 
341         verify(mockWifiManager, times(1)).getConnectionInfo();
342     }
343 
344     @Test
latestNetworkInfo_shouldBeFetchedInDisplayPreference()345     public void latestNetworkInfo_shouldBeFetchedInDisplayPreference() {
346         displayAndResume();
347 
348         verify(mockConnectivityManager, times(1)).getNetworkInfo(any(Network.class));
349     }
350 
351     @Test
networkCallback_shouldBeRegisteredOnResume()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
networkCallback_shouldBeUnregisteredOnPause()360     public void networkCallback_shouldBeUnregisteredOnPause() {
361         displayAndResume();
362         mController.onPause();
363 
364         verify(mockConnectivityManager, times(1))
365                 .unregisterNetworkCallback(mCallbackCaptor.getValue());
366     }
367 
368     @Test
entityHeader_shouldHaveIconSet()369     public void entityHeader_shouldHaveIconSet() {
370         Drawable expectedIcon = mockIconInjector.getIcon(LEVEL);
371 
372         displayAndResume();
373 
374         verify(mockHeaderController).setIcon(expectedIcon);
375     }
376 
377     @Test
entityHeader_shouldHaveLabelSetToSsid()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
entityHeader_shouldHaveSummarySet()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
signalStrengthPref_shouldHaveIconSet()398     public void signalStrengthPref_shouldHaveIconSet() {
399         displayAndResume();
400 
401         verify(mockSignalStrengthPref).setIcon(any(Drawable.class));
402     }
403 
404     @Test
signalStrengthPref_shouldHaveDetailTextSet()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
linkSpeedPref_shouldHaveDetailTextSet()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
linkSpeedPref_shouldNotShowIfNotSet()424     public void linkSpeedPref_shouldNotShowIfNotSet() {
425         when(mockWifiInfo.getLinkSpeed()).thenReturn(-1);
426 
427         displayAndResume();
428 
429         verify(mockLinkSpeedPref).setVisible(false);
430     }
431 
432     @Test
macAddressPref_shouldHaveDetailTextSet()433     public void macAddressPref_shouldHaveDetailTextSet() {
434         displayAndResume();
435 
436         verify(mockMacAddressPref).setDetailText(MAC_ADDRESS);
437     }
438 
439     @Test
ipAddressPref_shouldHaveDetailTextSet()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
gatewayAndSubnet_shouldHaveDetailTextSet()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
dnsServersPref_shouldHaveDetailTextSet()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
noCurrentNetwork_shouldFinishActivity()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
noLinkProperties_allIpDetailsHidden()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.
asString(LinkAddress l)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).
updateLinkProperties(LinkProperties lp)511     private void updateLinkProperties(LinkProperties lp) {
512         mCallbackCaptor.getValue().onLinkPropertiesChanged(mockNetwork, new LinkProperties(lp));
513     }
514 
updateNetworkCapabilities(NetworkCapabilities nc)515     private void updateNetworkCapabilities(NetworkCapabilities nc) {
516         mCallbackCaptor.getValue().onCapabilitiesChanged(mockNetwork, new NetworkCapabilities(nc));
517     }
518 
makeNetworkCapabilities()519     private NetworkCapabilities makeNetworkCapabilities() {
520         NetworkCapabilities nc = new NetworkCapabilities();
521         nc.clearAll();
522         nc.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
523         return nc;
524     }
525 
verifyDisplayedIpv6Addresses(InOrder inOrder, LinkAddress... addresses)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
onLinkPropertiesChanged_updatesFields()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
onCapabilitiesChanged_callsRefreshIfNecessary()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
canForgetNetwork_noNetwork()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
canForgetNetwork_ephemeral()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
canForgetNetwork_saved()648     public void canForgetNetwork_saved() {
649         displayAndResume();
650 
651         verify(mockButtonsPref).setButton1Visible(true);
652     }
653 
654     @Test
canForgetNetwork_lockedDown()655     public void canForgetNetwork_lockedDown() {
656         lockDownNetwork();
657 
658         displayAndResume();
659 
660         verify(mockButtonsPref).setButton1Visible(false);
661     }
662 
663     @Test
canModifyNetwork_saved()664     public void canModifyNetwork_saved() {
665         assertThat(mController.canModifyNetwork()).isTrue();
666     }
667 
668     @Test
canModifyNetwork_lockedDown()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      */
lockDownNetwork()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
forgetNetwork_ephemeral()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
forgetNetwork_saved()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
networkStateChangedIntent_shouldRefetchInfo()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
rssiChangedIntent_shouldRefetchInfo()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
networkDisconnectedState_shouldFinishActivity()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
networkOnLost_shouldFinishActivity()756     public void networkOnLost_shouldFinishActivity() {
757         displayAndResume();
758 
759         mCallbackCaptor.getValue().onLost(mockNetwork);
760 
761         verify(mockActivity).finish();
762     }
763 
764     @Test
ipv6AddressPref_shouldHaveHostAddressTextSet()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
ipv6AddressPref_shouldNotBeSelectable()781     public void ipv6AddressPref_shouldNotBeSelectable() {
782         mLinkProperties.addLinkAddress(Constants.IPV6_GLOBAL2);
783 
784         displayAndResume();
785 
786         assertThat(mockIpv6AddressesPref.isSelectable()).isFalse();
787     }
788 
789     @Test
captivePortal_shouldShowSignInButton()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
testSignInButton_shouldStartCaptivePortalApp()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
testRefreshRssiViews_shouldNotUpdateIfLevelIsSame()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
testRefreshRssiViews_shouldUpdateOnLevelChange()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