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