Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 399e1a58 authored by Amin Shaikh's avatar Amin Shaikh
Browse files

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
parent 665c1ced
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1886,11 +1886,11 @@
    <!-- Wifi Network Details -->
    <!-- Wifi details preference title to display router IP subnet mask -->
    <string name="wifi_details_subnet_mask">Subnet Mask</string>
    <string name="wifi_details_subnet_mask">Subnet mask</string>
    <!-- Wifi details preference title to display router DNS info -->
    <string name="wifi_details_dns">DNS</string>
    <!-- Wifi details preference category title for IPv6 information -->
    <string name="wifi_details_ipv6_address_header">IPv6 Addresses</string>
    <string name="wifi_details_ipv6_address_header">IPv6 addresses</string>
    <!-- Wifi saved access points.  Used as a label under the shortcut icon that goes to Wifi saved access points. [CHAR LIMIT=20] -->
    <string name="wifi_saved_access_points_label">Saved networks</string>
+5 −1
Original line number Diff line number Diff line
@@ -54,12 +54,16 @@
    <PreferenceCategory
            android:key="ip_details_category"
            android:title="@string/wifi_setup_detail">
        <com.android.settings.wifi.WifiDetailPreference
            android:key="mac_address"
            android:title="@string/wifi_advanced_mac_address_title"
            android:selectable="false"/>
        <com.android.settings.wifi.WifiDetailPreference
                android:key="ip_address"
                android:title="@string/wifi_ip_address"
                android:selectable="false"/>
        <com.android.settings.wifi.WifiDetailPreference
                android:key="router"
                android:key="gateway"
                android:title="@string/wifi_gateway"
                android:selectable="false"/>
        <com.android.settings.wifi.WifiDetailPreference
+72 −37
Original line number Diff line number Diff line
@@ -18,18 +18,20 @@ package com.android.settings.wifi.details;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.IpPrefix;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkBadging;
import android.net.NetworkInfo;
import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;
import android.text.TextUtils;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;
@@ -44,7 +46,9 @@ import com.android.settingslib.wifi.AccessPoint;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.StringJoiner;

/**
 * Controller for logic pertaining to displaying Wifi information for the
@@ -65,9 +69,11 @@ public class WifiDetailPreferenceController extends PreferenceController impleme
    @VisibleForTesting
    static final String KEY_SECURITY_PREF = "security";
    @VisibleForTesting
    static final String KEY_MAC_ADDRESS_PREF = "mac_address";
    @VisibleForTesting
    static final String KEY_IP_ADDRESS_PREF = "ip_address";
    @VisibleForTesting
    static final String KEY_ROUTER_PREF = "router";
    static final String KEY_GATEWAY_PREF = "gateway";
    @VisibleForTesting
    static final String KEY_SUBNET_MASK_PREF = "subnet_mask";
    @VisibleForTesting
@@ -83,6 +89,7 @@ public class WifiDetailPreferenceController extends PreferenceController impleme
    private WifiConfiguration mWifiConfig;
    private WifiInfo mWifiInfo;
    private final WifiManager mWifiManager;
    private final ConnectivityManager mConnectivityManager;

    // Preferences - in order of appearance
    private Preference mConnectionDetailPref;
@@ -90,14 +97,15 @@ public class WifiDetailPreferenceController extends PreferenceController impleme
    private WifiDetailPreference mLinkSpeedPref;
    private WifiDetailPreference mFrequencyPref;
    private WifiDetailPreference mSecurityPref;
    private WifiDetailPreference mMacAddressPref;
    private WifiDetailPreference mIpAddressPref;
    private WifiDetailPreference mRouterPref;
    private WifiDetailPreference mGatewayPref;
    private WifiDetailPreference mSubnetPref;
    private WifiDetailPreference mDnsPref;
    private PreferenceCategory mIpv6AddressCategory;

    public WifiDetailPreferenceController(AccessPoint accessPoint, Context context,
            Lifecycle lifecycle, WifiManager wifiManager) {
            Lifecycle lifecycle, WifiManager wifiManager, ConnectivityManager connectivityManager) {
        super(context);

        mAccessPoint = accessPoint;
@@ -106,6 +114,7 @@ public class WifiDetailPreferenceController extends PreferenceController impleme
        mSignalStr = context.getResources().getStringArray(R.array.wifi_signal);
        mWifiConfig = accessPoint.getConfig();
        mWifiManager = wifiManager;
        mConnectivityManager = connectivityManager;
        mWifiInfo = wifiManager.getConnectionInfo();

        lifecycle.addObserver(this);
@@ -136,8 +145,9 @@ public class WifiDetailPreferenceController extends PreferenceController impleme
        mFrequencyPref = (WifiDetailPreference) screen.findPreference(KEY_FREQUENCY_PREF);
        mSecurityPref = (WifiDetailPreference) screen.findPreference(KEY_SECURITY_PREF);

        mMacAddressPref = (WifiDetailPreference) screen.findPreference(KEY_MAC_ADDRESS_PREF);
        mIpAddressPref = (WifiDetailPreference) screen.findPreference(KEY_IP_ADDRESS_PREF);
        mRouterPref = (WifiDetailPreference) screen.findPreference(KEY_ROUTER_PREF);
        mGatewayPref = (WifiDetailPreference) screen.findPreference(KEY_GATEWAY_PREF);
        mSubnetPref = (WifiDetailPreference) screen.findPreference(KEY_SUBNET_MASK_PREF);
        mDnsPref = (WifiDetailPreference) screen.findPreference(KEY_DNS_PREF);

@@ -174,6 +184,9 @@ public class WifiDetailPreferenceController extends PreferenceController impleme
        mConnectionDetailPref.setIcon(wifiIcon);
        mConnectionDetailPref.setTitle(mAccessPoint.getSettingsSummary());

        // MAC Address Pref
        mMacAddressPref.setDetailText(mWifiInfo.getMacAddress());

        // Signal Strength Pref
        Drawable wifiIconDark = wifiIcon.getConstantState().newDrawable().mutate();
        wifiIconDark.setTint(mContext.getResources().getColor(
@@ -184,6 +197,8 @@ public class WifiDetailPreferenceController extends PreferenceController impleme
        mSignalStrengthPref.setDetailText(mSignalStr[summarySignalLevel]);

        // Link Speed Pref
        int linkSpeedMbps = mWifiInfo.getLinkSpeed();
        mLinkSpeedPref.setVisible(linkSpeedMbps >= 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<InetAddress> addresses = prop.getAllAddresses();
        LinkProperties linkProperties = mConnectivityManager.getLinkProperties(currentNetwork);
        if (linkProperties == null) {
            return;
        }
        List<InetAddress> 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);
        if (!TextUtils.isEmpty(subnet)) {
            mSubnetPref.setDetailText(subnet);
            mSubnetPref.setVisible(true);
        }

            router = mWifiManager.getWifiApConfiguration().getStaticIpConfiguration().gateway
                    .getHostAddress();
        if (!TextUtils.isEmpty(gateway)) {
            mGatewayPref.setDetailText(gateway);
            mGatewayPref.setVisible(true);
        }
        mRouterPref.setDetailText(router);
        mSubnetPref.setDetailText(subnetMask);

        // Set DNS
        addresses = prop.getDnsServers();
        StringBuilder builder = new StringBuilder();
        // 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);
        }
    }

        // 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());
    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());
    }

    /**
+3 −4
Original line number Diff line number Diff line
@@ -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<PreferenceController> controllers = new ArrayList(1);
        controllers.add(mWifiDetailPreferenceController);
+131 −7
Original line number Diff line number Diff line
@@ -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();
    }