From 399e1a58107b0d7864dfefb198e8a687d63f2d06 Mon Sep 17 00:00:00 2001 From: Amin Shaikh Date: Fri, 7 Apr 2017 14:01:41 -0700 Subject: [PATCH] Wi-Fi network details page fixes. - Fix NPE in WifiDetailPreferenceController#setIpText - Add MAC address preference in the details section - Set subnet mask and gateway preferences - Do not show IP information preferences if no information is available - Fix string capitalization errors - Only show IPv4 DNS servers under "Network details" section Bug: 36483230 Bug: 37096448 Bug: 36482499 Bug: 37165860 Test: m RunSettingsRoboTests Change-Id: I0e3f0ccfc4a8d802b51ed6b3be81c75e384dd06f --- res/values/strings.xml | 4 +- res/xml/wifi_network_details_fragment.xml | 6 +- .../WifiDetailPreferenceController.java | 115 ++++++++++----- .../details/WifiNetworkDetailsFragment.java | 7 +- .../WifiDetailPreferenceControllerTest.java | 138 +++++++++++++++++- 5 files changed, 216 insertions(+), 54 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index fba0ef502ac..475fb85bdf2 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1886,11 +1886,11 @@ - Subnet Mask + Subnet mask DNS - IPv6 Addresses + IPv6 addresses Saved networks diff --git a/res/xml/wifi_network_details_fragment.xml b/res/xml/wifi_network_details_fragment.xml index 09bcf863747..5b20d595daf 100644 --- a/res/xml/wifi_network_details_fragment.xml +++ b/res/xml/wifi_network_details_fragment.xml @@ -54,12 +54,16 @@ + = 0); mLinkSpeedPref.setDetailText(mContext.getString( R.string.link_speed, mWifiInfo.getLinkSpeed())); @@ -203,67 +218,87 @@ public class WifiDetailPreferenceController extends PreferenceController impleme } private void setIpText() { + // Reset all fields mIpv6AddressCategory.removeAll(); mIpv6AddressCategory.setVisible(false); + mIpAddressPref.setVisible(false); + mSubnetPref.setVisible(false); + mGatewayPref.setVisible(false); + mDnsPref.setVisible(false); Network currentNetwork = mWifiManager.getCurrentNetwork(); if (currentNetwork == null) { return; } - ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); - LinkProperties prop = cm.getLinkProperties(currentNetwork); - List addresses = prop.getAllAddresses(); + LinkProperties linkProperties = mConnectivityManager.getLinkProperties(currentNetwork); + if (linkProperties == null) { + return; + } + List addresses = linkProperties.getAddresses(); - // Set ip addresses + // Set IPv4 and Ipv6 addresses for (int i = 0; i < addresses.size(); i++) { InetAddress addr = addresses.get(i); if (addr instanceof Inet4Address) { mIpAddressPref.setDetailText(addr.getHostAddress()); + mIpAddressPref.setVisible(true); } else if (addr instanceof Inet6Address) { String ip = addr.getHostAddress(); Preference pref = new Preference(mPrefContext); pref.setKey(ip); pref.setTitle(ip); mIpv6AddressCategory.addPreference(pref); - mIpv6AddressCategory.setVisible(true); // TODO(sghuman): Make sure to + mIpv6AddressCategory.setVisible(true); } } - String subnetMask = null; - String router; - DhcpInfo dhcp = mWifiManager.getDhcpInfo(); - if (dhcp != null) { - if (dhcp.netmask == 0) { - Log.e(TAG, "invalid netmask value of 0 for DhcpInfo: " + dhcp); - mSubnetPref.setVisible(false); - } else { - subnetMask = NetworkUtils.intToInetAddress(dhcp.netmask).getHostAddress(); - mSubnetPref.setVisible(true); + // Set up IPv4 gateway and subnet mask + String gateway = null; + String subnet = null; + for (RouteInfo routeInfo : linkProperties.getRoutes()) { + if (routeInfo.hasGateway() && routeInfo.getGateway() instanceof Inet4Address) { + gateway = routeInfo.getGateway().getHostAddress(); + } + IpPrefix ipPrefix = routeInfo.getDestination(); + if (ipPrefix != null && ipPrefix.getAddress() instanceof Inet4Address + && ipPrefix.getPrefixLength() > 0) { + subnet = ipv4PrefixLengthToSubnetMask(ipPrefix.getPrefixLength()); } - - router = NetworkUtils.intToInetAddress(dhcp.gateway).getHostAddress(); - } else { // Statically configured IP - - // TODO(sghuman): How do we get subnet mask for static ips? - mSubnetPref.setVisible(false); - - router = mWifiManager.getWifiApConfiguration().getStaticIpConfiguration().gateway - .getHostAddress(); } - mRouterPref.setDetailText(router); - mSubnetPref.setDetailText(subnetMask); - // Set DNS - addresses = prop.getDnsServers(); - StringBuilder builder = new StringBuilder(); - - // addresses is backed by an ArrayList, so use a hand-written iterator for performance gains - for (int i = 0; i < addresses.size(); i++) { - if (i > 0) builder.append(", "); - builder.append(addresses.get(i).getHostAddress()); + if (!TextUtils.isEmpty(subnet)) { + mSubnetPref.setDetailText(subnet); + mSubnetPref.setVisible(true); + } + + if (!TextUtils.isEmpty(gateway)) { + mGatewayPref.setDetailText(gateway); + mGatewayPref.setVisible(true); + } + + // Set IPv4 DNS addresses + StringJoiner stringJoiner = new StringJoiner(","); + for (InetAddress dnsServer : linkProperties.getDnsServers()) { + if (dnsServer instanceof Inet4Address) { + stringJoiner.add(dnsServer.getHostAddress()); + } + } + String dnsText = stringJoiner.toString(); + if (!dnsText.isEmpty()) { + mDnsPref.setDetailText(dnsText); + mDnsPref.setVisible(true); + } + } + + private static String ipv4PrefixLengthToSubnetMask(int prefixLength) { + try { + InetAddress all = InetAddress.getByAddress( + new byte[]{(byte) 255, (byte) 255, (byte) 255, (byte) 255}); + return NetworkUtils.getNetworkPart(all, prefixLength).getHostAddress(); + } catch (UnknownHostException e) { + return null; } - mDnsPref.setDetailText(builder.toString()); } /** diff --git a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java index 7ebde38a687..ebd11434ce4 100644 --- a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java +++ b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java @@ -16,6 +16,7 @@ package com.android.settings.wifi.details; import android.content.Context; +import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.os.Bundle; import android.widget.Button; @@ -45,13 +46,10 @@ public class WifiNetworkDetailsFragment extends DashboardFragment { private AccessPoint mAccessPoint; private Button mForgetButton; private WifiDetailPreferenceController mWifiDetailPreferenceController; - private WifiManager mWifiManager; @Override public void onAttach(Context context) { mAccessPoint = new AccessPoint(context, getArguments()); - mWifiManager = context.getSystemService(WifiManager.class); - super.onAttach(context); } @@ -95,7 +93,8 @@ public class WifiNetworkDetailsFragment extends DashboardFragment { mAccessPoint, context, getLifecycle(), - mWifiManager); + context.getSystemService(WifiManager.class), + context.getSystemService(ConnectivityManager.class)); ArrayList controllers = new ArrayList(1); controllers.add(mWifiDetailPreferenceController); diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java index f60c106c0b8..7cb69ea02dd 100644 --- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java @@ -18,14 +18,22 @@ package com.android.settings.wifi.details; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.graphics.drawable.Drawable; +import android.net.ConnectivityManager; +import android.net.IpPrefix; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.Network; import android.net.NetworkBadging; import android.net.NetworkInfo; +import android.net.RouteInfo; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; @@ -46,8 +54,14 @@ import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +import java.net.InetAddress; +import java.net.UnknownHostException; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) @@ -56,28 +70,35 @@ public class WifiDetailPreferenceControllerTest { private static final int LEVEL = 1; private static final int RSSI = -55; private static final int LINK_SPEED = 123; + private static final String MAC_ADDRESS = WifiInfo.DEFAULT_MAC_ADDRESS; private static final String SECURITY = "None"; + private InetAddress mIpv4Address; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) private PreferenceScreen mockScreen; @Mock private AccessPoint mockAccessPoint; @Mock private WifiManager mockWifiManager; + @Mock private ConnectivityManager mockConnectivityManager; @Mock private NetworkInfo mockNetworkInfo; @Mock private WifiConfiguration mockWifiConfig; @Mock private WifiInfo mockWifiInfo; + @Mock private Network mockNetwork; @Mock private Preference mockConnectionDetailPref; @Mock private WifiDetailPreference mockSignalStrengthPref; @Mock private WifiDetailPreference mockLinkSpeedPref; @Mock private WifiDetailPreference mockFrequencyPref; @Mock private WifiDetailPreference mockSecurityPref; + @Mock private WifiDetailPreference mockMacAddressPref; @Mock private WifiDetailPreference mockIpAddressPref; - @Mock private WifiDetailPreference mockRouterPref; + @Mock private WifiDetailPreference mockGatewayPref; @Mock private WifiDetailPreference mockSubnetPref; @Mock private WifiDetailPreference mockDnsPref; @Mock private PreferenceCategory mockIpv6AddressCategory; + private LinkProperties mLinkProperties; private Context mContext = RuntimeEnvironment.application; private Lifecycle mLifecycle; private WifiDetailPreferenceController mController; @@ -88,6 +109,13 @@ public class WifiDetailPreferenceControllerTest { mLifecycle = new Lifecycle(); + try { + mIpv4Address = InetAddress.getByAddress( + new byte[] { (byte) 255, (byte) 255, (byte) 255, (byte) 255 }); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + when(mockAccessPoint.getConfig()).thenReturn(mockWifiConfig); when(mockAccessPoint.getLevel()).thenReturn(LEVEL); when(mockAccessPoint.getNetworkInfo()).thenReturn(mockNetworkInfo); @@ -96,16 +124,20 @@ public class WifiDetailPreferenceControllerTest { when(mockWifiInfo.getLinkSpeed()).thenReturn(LINK_SPEED); when(mockWifiInfo.getRssi()).thenReturn(RSSI); + when(mockWifiInfo.getMacAddress()).thenReturn(MAC_ADDRESS); when(mockWifiManager.getConnectionInfo()).thenReturn(mockWifiInfo); + when(mockWifiManager.getCurrentNetwork()).thenReturn(mockNetwork); + mLinkProperties = new LinkProperties(); + when(mockConnectivityManager.getLinkProperties(mockNetwork)).thenReturn(mLinkProperties); + mController = new WifiDetailPreferenceController( - mockAccessPoint, mContext, mLifecycle, mockWifiManager); + mockAccessPoint, mContext, mLifecycle, mockWifiManager, mockConnectivityManager); setupMockedPreferenceScreen(); } private void setupMockedPreferenceScreen() { - when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_CONNECTION_DETAIL_PREF)) .thenReturn(mockConnectionDetailPref); when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_SIGNAL_STRENGTH_PREF)) @@ -116,10 +148,12 @@ public class WifiDetailPreferenceControllerTest { .thenReturn(mockFrequencyPref); when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_SECURITY_PREF)) .thenReturn(mockSecurityPref); + when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_MAC_ADDRESS_PREF)) + .thenReturn(mockMacAddressPref); when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_IP_ADDRESS_PREF)) .thenReturn(mockIpAddressPref); - when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_ROUTER_PREF)) - .thenReturn(mockRouterPref); + when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_GATEWAY_PREF)) + .thenReturn(mockGatewayPref); when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_SUBNET_MASK_PREF)) .thenReturn(mockSubnetPref); when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_DNS_PREF)) @@ -194,12 +228,102 @@ public class WifiDetailPreferenceControllerTest { verify(mockLinkSpeedPref).setDetailText(expectedLinkSpeed); } + @Test + public void linkSpeedPref_shouldNotShowIfNotSet() { + when(mockWifiInfo.getLinkSpeed()).thenReturn(-1); + + mController.onResume(); + + verify(mockLinkSpeedPref).setVisible(false); + } + + @Test + public void macAddressPref_shouldHaveDetailTextSet() { + mController.onResume(); + + verify(mockMacAddressPref).setDetailText(MAC_ADDRESS); + } + + @Test + public void ipAddressPref_shouldHaveDetailTextSet() { + LinkAddress ipv4Address = new LinkAddress(mIpv4Address, 32); + + mLinkProperties.addLinkAddress(ipv4Address); + + mController.onResume(); + + verify(mockIpAddressPref).setDetailText(mIpv4Address.getHostAddress()); + } + + @Test + public void gatewayAndSubnet_shouldHaveDetailTextSet() { + int prefixLength = 24; + IpPrefix subnet = new IpPrefix(mIpv4Address, prefixLength); + InetAddress gateway = mIpv4Address; + mLinkProperties.addRoute(new RouteInfo(subnet, gateway)); + + mController.onResume(); + + verify(mockSubnetPref).setDetailText("255.255.255.0"); + verify(mockGatewayPref).setDetailText(mIpv4Address.getHostAddress()); + } + + @Test + public void dnsServersPref_shouldHaveDetailTextSet() throws UnknownHostException { + mLinkProperties.addDnsServer(InetAddress.getByAddress(new byte[]{8,8,4,4})); + mLinkProperties.addDnsServer(InetAddress.getByAddress(new byte[]{8,8,8,8})); + + mController.onResume(); + + verify(mockDnsPref).setDetailText("8.8.4.4,8.8.8.8"); + } + + @Test + public void noCurrentNetwork_allIpDetailsHidden() { + when(mockWifiManager.getCurrentNetwork()).thenReturn(null); + reset(mockIpv6AddressCategory, mockIpAddressPref, mockSubnetPref, mockGatewayPref, + mockDnsPref); + + mController.onResume(); + + verify(mockIpv6AddressCategory).setVisible(false); + verify(mockIpAddressPref).setVisible(false); + verify(mockSubnetPref).setVisible(false); + verify(mockGatewayPref).setVisible(false); + verify(mockDnsPref).setVisible(false); + verify(mockIpv6AddressCategory, never()).setVisible(true); + verify(mockIpAddressPref, never()).setVisible(true); + verify(mockSubnetPref, never()).setVisible(true); + verify(mockGatewayPref, never()).setVisible(true); + verify(mockDnsPref, never()).setVisible(true); + } + + @Test + public void noLinkProperties_allIpDetailsHidden() { + when(mockConnectivityManager.getLinkProperties(mockNetwork)).thenReturn(null); + reset(mockIpv6AddressCategory, mockIpAddressPref, mockSubnetPref, mockGatewayPref, + mockDnsPref); + + mController.onResume(); + + verify(mockIpv6AddressCategory).setVisible(false); + verify(mockIpAddressPref).setVisible(false); + verify(mockSubnetPref).setVisible(false); + verify(mockGatewayPref).setVisible(false); + verify(mockDnsPref).setVisible(false); + verify(mockIpv6AddressCategory, never()).setVisible(true); + verify(mockIpAddressPref, never()).setVisible(true); + verify(mockSubnetPref, never()).setVisible(true); + verify(mockGatewayPref, never()).setVisible(true); + verify(mockDnsPref, never()).setVisible(true); + } + @Test public void canForgetNetwork_noNetwork() { when(mockAccessPoint.getConfig()).thenReturn(null); mController = new WifiDetailPreferenceController( - mockAccessPoint, mContext, mLifecycle, mockWifiManager); + mockAccessPoint, mContext, mLifecycle, mockWifiManager, mockConnectivityManager); assertThat(mController.canForgetNetwork()).isFalse(); } @@ -210,7 +334,7 @@ public class WifiDetailPreferenceControllerTest { when(mockAccessPoint.getConfig()).thenReturn(null); mController = new WifiDetailPreferenceController( - mockAccessPoint, mContext, mLifecycle, mockWifiManager); + mockAccessPoint, mContext, mLifecycle, mockWifiManager, mockConnectivityManager); assertThat(mController.canForgetNetwork()).isTrue(); }