Home | History | Annotate | Download | only in details
      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