Loading res/xml/wifi_network_details_fragment.xml +6 −2 Original line number Diff line number Diff line Loading @@ -82,8 +82,12 @@ <!-- IPv6 Details --> <PreferenceCategory android:key="ipv6_details_category" android:key="ipv6_category" android:title="@string/wifi_details_ipv6_address_header" android:selectable="false"> <Preference android:key="ipv6_addresses" android:selectable="false"/> </PreferenceCategory> </PreferenceScreen> src/com/android/settings/wifi/WifiDetailPreference.java +2 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.settings.wifi; import android.content.Context; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceViewHolder; import android.text.TextUtils; import android.util.AttributeSet; import android.widget.TextView; Loading @@ -37,6 +38,7 @@ public class WifiDetailPreference extends Preference { } public void setDetailText(String text) { if (TextUtils.equals(mDetailText, text)) return; mDetailText = text; notifyChanged(); } Loading src/com/android/settings/wifi/details/WifiDetailPreferenceController.java +57 −59 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.graphics.drawable.Drawable; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkBadging; Loading Loading @@ -67,6 +68,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.List; import java.util.StringJoiner; import java.util.stream.Collectors; /** * Controller for logic pertaining to displaying Wifi information for the Loading Loading @@ -100,7 +102,9 @@ public class WifiDetailPreferenceController extends PreferenceController impleme @VisibleForTesting static final String KEY_DNS_PREF = "dns"; @VisibleForTesting static final String KEY_IPV6_ADDRESS_CATEGORY = "ipv6_details_category"; static final String KEY_IPV6_CATEGORY = "ipv6_category"; @VisibleForTesting static final String KEY_IPV6_ADDRESSES_PREF = "ipv6_addresses"; private AccessPoint mAccessPoint; private final ConnectivityManagerWrapper mConnectivityManagerWrapper; Loading Loading @@ -133,8 +137,9 @@ public class WifiDetailPreferenceController extends PreferenceController impleme private WifiDetailPreference mGatewayPref; private WifiDetailPreference mSubnetPref; private WifiDetailPreference mDnsPref; private PreferenceCategory mIpv6Category; private Preference mIpv6AddressPref; private PreferenceCategory mIpv6AddressCategory; private final IntentFilter mFilter; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override Loading Loading @@ -241,8 +246,8 @@ public class WifiDetailPreferenceController extends PreferenceController impleme mSubnetPref = (WifiDetailPreference) screen.findPreference(KEY_SUBNET_MASK_PREF); mDnsPref = (WifiDetailPreference) screen.findPreference(KEY_DNS_PREF); mIpv6AddressCategory = (PreferenceCategory) screen.findPreference(KEY_IPV6_ADDRESS_CATEGORY); mIpv6Category = (PreferenceCategory) screen.findPreference(KEY_IPV6_CATEGORY); mIpv6AddressPref = (Preference) screen.findPreference(KEY_IPV6_ADDRESSES_PREF); mSecurityPref.setDetailText(mAccessPoint.getSecurityString(false /* concise */)); mForgetButton = (Button) mButtonsPref.findViewById(R.id.forget_button); Loading Loading @@ -315,8 +320,6 @@ public class WifiDetailPreferenceController extends PreferenceController impleme mFrequencyPref.setDetailText(band); updateIpLayerInfo(); mButtonsPref.setVisible(mForgetButton.getVisibility() == View.VISIBLE || mSignInButton.getVisibility() == View.VISIBLE); } private void exitActivity() { Loading Loading @@ -348,74 +351,69 @@ public class WifiDetailPreferenceController extends PreferenceController impleme mSignalStrengthPref.setDetailText(mSignalStr[summarySignalLevel]); } private void updatePreference(WifiDetailPreference pref, String detailText) { if (!TextUtils.isEmpty(detailText)) { pref.setDetailText(detailText); pref.setVisible(true); } else { pref.setVisible(false); } } private void updateIpLayerInfo() { mSignInButton.setVisibility(canSignIntoNetwork() ? View.VISIBLE : View.INVISIBLE); mButtonsPref.setVisible(mForgetButton.getVisibility() == View.VISIBLE || mSignInButton.getVisibility() == View.VISIBLE); // Reset all fields mIpv6AddressCategory.removeAll(); mIpv6AddressCategory.setVisible(false); if (mNetwork == null || mLinkProperties == null) { mIpAddressPref.setVisible(false); mSubnetPref.setVisible(false); mGatewayPref.setVisible(false); mDnsPref.setVisible(false); if (mNetwork == null || mLinkProperties == null) { mIpv6Category.setVisible(false); return; } List<InetAddress> addresses = mLinkProperties.getAddresses(); // 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); pref.setSelectable(false); mIpv6AddressCategory.addPreference(pref); mIpv6AddressCategory.setVisible(true); // Find IPv4 and IPv6 addresses. String ipv4Address = null; String subnet = null; StringJoiner ipv6Addresses = new StringJoiner("\n"); for (LinkAddress addr : mLinkProperties.getLinkAddresses()) { if (addr.getAddress() instanceof Inet4Address) { ipv4Address = addr.getAddress().getHostAddress(); subnet = ipv4PrefixLengthToSubnetMask(addr.getPrefixLength()); } else if (addr.getAddress() instanceof Inet6Address) { ipv6Addresses.add(addr.getAddress().getHostAddress()); } } // Set up IPv4 gateway and subnet mask // Find IPv4 default gateway. String gateway = null; String subnet = null; for (RouteInfo routeInfo : mLinkProperties.getRoutes()) { if (routeInfo.hasGateway() && routeInfo.getGateway() instanceof Inet4Address) { if (routeInfo.isIPv4Default() && routeInfo.hasGateway()) { gateway = routeInfo.getGateway().getHostAddress(); } IpPrefix ipPrefix = routeInfo.getDestination(); if (ipPrefix != null && ipPrefix.getAddress() instanceof Inet4Address && ipPrefix.getPrefixLength() > 0) { subnet = ipv4PrefixLengthToSubnetMask(ipPrefix.getPrefixLength()); break; } } if (!TextUtils.isEmpty(subnet)) { mSubnetPref.setDetailText(subnet); mSubnetPref.setVisible(true); } // Find IPv4 DNS addresses. String dnsServers = mLinkProperties.getDnsServers().stream() .filter(Inet4Address.class::isInstance) .map(InetAddress::getHostAddress) .collect(Collectors.joining(",")); if (!TextUtils.isEmpty(gateway)) { mGatewayPref.setDetailText(gateway); mGatewayPref.setVisible(true); } // Update UI. updatePreference(mIpAddressPref, ipv4Address); updatePreference(mSubnetPref, subnet); updatePreference(mGatewayPref, gateway); updatePreference(mDnsPref, dnsServers); // Set IPv4 DNS addresses StringJoiner stringJoiner = new StringJoiner(","); for (InetAddress dnsServer : mLinkProperties.getDnsServers()) { if (dnsServer instanceof Inet4Address) { stringJoiner.add(dnsServer.getHostAddress()); } } String dnsText = stringJoiner.toString(); if (!dnsText.isEmpty()) { mDnsPref.setDetailText(dnsText); mDnsPref.setVisible(true); if (ipv6Addresses.length() > 0) { mIpv6AddressPref.setSummary(ipv6Addresses.toString()); mIpv6Category.setVisible(true); } else { mIpv6Category.setVisible(false); } } Loading tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java +159 −44 Original line number Diff line number Diff line Loading @@ -75,9 +75,13 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) Loading @@ -89,9 +93,6 @@ public class WifiDetailPreferenceControllerTest { private static final String MAC_ADDRESS = WifiInfo.DEFAULT_MAC_ADDRESS; private static final String SECURITY = "None"; private InetAddress mIpv4Address; private Inet6Address mIpv6Address; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private PreferenceScreen mockScreen; Loading Loading @@ -120,35 +121,76 @@ public class WifiDetailPreferenceControllerTest { @Mock private WifiDetailPreference mockSubnetPref; @Mock private WifiDetailPreference mockDnsPref; @Mock private Button mockForgetButton; @Mock private PreferenceCategory mockIpv6AddressCategory; @Mock private PreferenceCategory mockIpv6Category; @Mock private WifiDetailPreference mockIpv6AddressesPref; @Captor private ArgumentCaptor<NetworkCallback> mCallbackCaptor; @Captor private ArgumentCaptor<View.OnClickListener> mForgetClickListener; @Captor private ArgumentCaptor<Preference> mIpv6AddressCaptor; private Context mContext = RuntimeEnvironment.application; private Lifecycle mLifecycle; private LinkProperties mLinkProperties; private WifiDetailPreferenceController mController; // This class exists so that these values can be made static final. They can't be static final // members of the test class, because any attempt to call IpPrefix or RouteInfo constructors // during static initialization of the test class results in NoSuchMethorError being thrown // when the test is run. private static class Constants { static final int IPV4_PREFIXLEN = 25; static final LinkAddress IPV4_ADDR; static final Inet4Address IPV4_GATEWAY; static final RouteInfo IPV4_DEFAULT; static final RouteInfo IPV4_SUBNET; static final LinkAddress IPV6_LINKLOCAL; static final LinkAddress IPV6_GLOBAL1; static final LinkAddress IPV6_GLOBAL2; static final InetAddress IPV4_DNS1; static final InetAddress IPV4_DNS2; static final InetAddress IPV6_DNS; private static LinkAddress ipv6LinkAddress(String addr) throws UnknownHostException { return new LinkAddress(InetAddress.getByName(addr), 64); } private static LinkAddress ipv4LinkAddress(String addr, int prefixlen) throws UnknownHostException { return new LinkAddress(InetAddress.getByName(addr), prefixlen); } static { try { // We create our test constants in these roundabout ways because the robolectric // shadows don't contain NetworkUtils.parseNumericAddress and other utility methods, // so the easy ways to do things fail with NoSuchMethodError. IPV4_ADDR = ipv4LinkAddress("192.0.2.2", IPV4_PREFIXLEN); IPV4_GATEWAY = (Inet4Address) InetAddress.getByName("192.0.2.127"); final Inet4Address any4 = (Inet4Address) InetAddress.getByName("0.0.0.0"); IpPrefix subnet = new IpPrefix(IPV4_ADDR.getAddress(), IPV4_PREFIXLEN); IPV4_SUBNET = new RouteInfo(subnet, any4); IPV4_DEFAULT = new RouteInfo(new IpPrefix(any4, 0), IPV4_GATEWAY); IPV6_LINKLOCAL = ipv6LinkAddress("fe80::211:25ff:fef8:7cb2%1"); IPV6_GLOBAL1 = ipv6LinkAddress("2001:db8:1::211:25ff:fef8:7cb2"); IPV6_GLOBAL2 = ipv6LinkAddress("2001:db8:1::3dfe:8902:f98f:739d"); IPV4_DNS1 = InetAddress.getByName("8.8.8.8"); IPV4_DNS2 = InetAddress.getByName("8.8.4.4"); IPV6_DNS = InetAddress.getByName("2001:4860:4860::64"); } catch (UnknownHostException e) { throw new RuntimeException("Invalid hardcoded IP addresss: " + e); } } } @Before public void setUp() { MockitoAnnotations.initMocks(this); mLifecycle = new Lifecycle(); try { mIpv4Address = InetAddress.getByAddress( new byte[] { (byte) 255, (byte) 255, (byte) 255, (byte) 255 }); mIpv6Address = Inet6Address.getByAddress( "123", /* host */ new byte[] { (byte) 0xFE, (byte) 0x80, 0, 0, 0, 0, 0, 0, 0x02, 0x11, 0x25, (byte) 0xFF, (byte) 0xFE, (byte) 0xF8, (byte) 0x7C, (byte) 0xB2}, 1 /*scope id */); } catch (UnknownHostException e) { throw new RuntimeException(e); } when(mockAccessPoint.getConfig()).thenReturn(mockWifiConfig); when(mockAccessPoint.getLevel()).thenReturn(LEVEL); when(mockAccessPoint.getSecurityString(false)).thenReturn(SECURITY); Loading Loading @@ -217,8 +259,10 @@ public class WifiDetailPreferenceControllerTest { .thenReturn(mockSubnetPref); when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_DNS_PREF)) .thenReturn(mockDnsPref); when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_IPV6_ADDRESS_CATEGORY)) .thenReturn(mockIpv6AddressCategory); when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_IPV6_CATEGORY)) .thenReturn(mockIpv6Category); when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_IPV6_ADDRESSES_PREF)) .thenReturn(mockIpv6AddressesPref); } @Test Loading Loading @@ -330,26 +374,23 @@ public class WifiDetailPreferenceControllerTest { @Test public void ipAddressPref_shouldHaveDetailTextSet() { LinkAddress ipv4Address = new LinkAddress(mIpv4Address, 32); mLinkProperties.addLinkAddress(ipv4Address); mLinkProperties.addLinkAddress(Constants.IPV4_ADDR); mController.displayPreference(mockScreen); verify(mockIpAddressPref).setDetailText(mIpv4Address.getHostAddress()); verify(mockIpAddressPref).setDetailText(Constants.IPV4_ADDR.getAddress().getHostAddress()); } @Test public void gatewayAndSubnet_shouldHaveDetailTextSet() { int prefixLength = 24; IpPrefix subnet = new IpPrefix(mIpv4Address, prefixLength); InetAddress gateway = mIpv4Address; mLinkProperties.addRoute(new RouteInfo(subnet, gateway)); mLinkProperties.addLinkAddress(Constants.IPV4_ADDR); mLinkProperties.addRoute(Constants.IPV4_DEFAULT); mLinkProperties.addRoute(Constants.IPV4_SUBNET); mController.displayPreference(mockScreen); verify(mockSubnetPref).setDetailText("255.255.255.0"); verify(mockGatewayPref).setDetailText(mIpv4Address.getHostAddress()); verify(mockSubnetPref).setDetailText("255.255.255.128"); verify(mockGatewayPref).setDetailText("192.0.2.127"); } @Test Loading @@ -376,23 +417,96 @@ public class WifiDetailPreferenceControllerTest { @Test public void noLinkProperties_allIpDetailsHidden() { when(mockConnectivityManager.getLinkProperties(mockNetwork)).thenReturn(null); reset(mockIpv6AddressCategory, mockIpAddressPref, mockSubnetPref, mockGatewayPref, reset(mockIpv6Category, mockIpAddressPref, mockSubnetPref, mockGatewayPref, mockDnsPref); mController.displayPreference(mockScreen); verify(mockIpv6AddressCategory).setVisible(false); verify(mockIpv6Category).setVisible(false); verify(mockIpAddressPref).setVisible(false); verify(mockSubnetPref).setVisible(false); verify(mockGatewayPref).setVisible(false); verify(mockDnsPref).setVisible(false); verify(mockIpv6AddressCategory, never()).setVisible(true); verify(mockIpv6Category, never()).setVisible(true); verify(mockIpAddressPref, never()).setVisible(true); verify(mockSubnetPref, never()).setVisible(true); verify(mockGatewayPref, never()).setVisible(true); verify(mockDnsPref, never()).setVisible(true); } // Convenience method to convert a LinkAddress to a string without a prefix length. private String asString(LinkAddress l) { return l.getAddress().getHostAddress(); } // Pretend that the NetworkCallback was triggered with a new copy of lp. We need to create a // new copy because the code only updates if !mLinkProperties.equals(lp). private void updateLinkProperties(LinkProperties lp) { mCallbackCaptor.getValue().onLinkPropertiesChanged(mockNetwork, new LinkProperties(lp)); } private void verifyDisplayedIpv6Addresses(InOrder inOrder, LinkAddress... addresses) { String text = Arrays.stream(addresses) .map(address -> asString(address)) .collect(Collectors.joining("\n")); inOrder.verify(mockIpv6AddressesPref).setSummary(text); } @Test public void onLinkPropertiesChanged_updatesFields() { mController.displayPreference(mockScreen); mController.onResume(); InOrder inOrder = inOrder(mockIpAddressPref, mockGatewayPref, mockSubnetPref, mockDnsPref, mockIpv6Category, mockIpv6AddressesPref); LinkProperties lp = new LinkProperties(); lp.addLinkAddress(Constants.IPV6_LINKLOCAL); updateLinkProperties(lp); verifyDisplayedIpv6Addresses(inOrder, Constants.IPV6_LINKLOCAL); inOrder.verify(mockIpv6Category).setVisible(true); lp.addRoute(Constants.IPV4_DEFAULT); updateLinkProperties(lp); inOrder.verify(mockGatewayPref).setDetailText(Constants.IPV4_GATEWAY.getHostAddress()); inOrder.verify(mockGatewayPref).setVisible(true); lp.addLinkAddress(Constants.IPV4_ADDR); lp.addRoute(Constants.IPV4_SUBNET); updateLinkProperties(lp); inOrder.verify(mockIpAddressPref).setDetailText(asString(Constants.IPV4_ADDR)); inOrder.verify(mockIpAddressPref).setVisible(true); inOrder.verify(mockSubnetPref).setDetailText("255.255.255.128"); inOrder.verify(mockSubnetPref).setVisible(true); lp.addLinkAddress(Constants.IPV6_GLOBAL1); lp.addLinkAddress(Constants.IPV6_GLOBAL2); updateLinkProperties(lp); verifyDisplayedIpv6Addresses(inOrder, Constants.IPV6_LINKLOCAL, Constants.IPV6_GLOBAL1, Constants.IPV6_GLOBAL2); lp.removeLinkAddress(Constants.IPV6_GLOBAL1); updateLinkProperties(lp); verifyDisplayedIpv6Addresses(inOrder, Constants.IPV6_LINKLOCAL, Constants.IPV6_GLOBAL2); lp.addDnsServer(Constants.IPV6_DNS); updateLinkProperties(lp); inOrder.verify(mockDnsPref, never()).setVisible(true); lp.addDnsServer(Constants.IPV4_DNS1); lp.addDnsServer(Constants.IPV4_DNS2); updateLinkProperties(lp); inOrder.verify(mockDnsPref).setDetailText( Constants.IPV4_DNS1.getHostAddress() + "," + Constants.IPV4_DNS2.getHostAddress()); inOrder.verify(mockDnsPref).setVisible(true); } @Test public void canForgetNetwork_noNetwork() { when(mockAccessPoint.getConfig()).thenReturn(null); Loading Loading @@ -496,28 +610,29 @@ public class WifiDetailPreferenceControllerTest { @Test public void ipv6AddressPref_shouldHaveHostAddressTextSet() { LinkAddress ipv6Address = new LinkAddress(mIpv6Address, 128); mLinkProperties.addLinkAddress(ipv6Address); mLinkProperties.addLinkAddress(Constants.IPV6_LINKLOCAL); mLinkProperties.addLinkAddress(Constants.IPV6_GLOBAL1); mLinkProperties.addLinkAddress(Constants.IPV6_GLOBAL2); mController.displayPreference(mockScreen); ArgumentCaptor<Preference> preferenceCaptor = ArgumentCaptor.forClass(Preference.class); verify(mockIpv6AddressCategory).addPreference(preferenceCaptor.capture()); assertThat(preferenceCaptor.getValue().getTitle()).isEqualTo(mIpv6Address.getHostAddress()); List <Preference> addrs = mIpv6AddressCaptor.getAllValues(); String expectedAddresses = String.join("\n", asString(Constants.IPV6_LINKLOCAL), asString(Constants.IPV6_GLOBAL1), asString(Constants.IPV6_GLOBAL2)); verify(mockIpv6AddressesPref).setSummary(expectedAddresses); } @Test public void ipv6AddressPref_shouldNotBeSelectable() { LinkAddress ipv6Address = new LinkAddress(mIpv6Address, 128); mLinkProperties.addLinkAddress(ipv6Address); mLinkProperties.addLinkAddress(Constants.IPV6_GLOBAL2); mController.displayPreference(mockScreen); ArgumentCaptor<Preference> preferenceCaptor = ArgumentCaptor.forClass(Preference.class); verify(mockIpv6AddressCategory).addPreference(preferenceCaptor.capture()); assertThat(preferenceCaptor.getValue().isSelectable()).isFalse(); assertThat(mockIpv6AddressesPref.isSelectable()).isFalse(); } @Test Loading Loading
res/xml/wifi_network_details_fragment.xml +6 −2 Original line number Diff line number Diff line Loading @@ -82,8 +82,12 @@ <!-- IPv6 Details --> <PreferenceCategory android:key="ipv6_details_category" android:key="ipv6_category" android:title="@string/wifi_details_ipv6_address_header" android:selectable="false"> <Preference android:key="ipv6_addresses" android:selectable="false"/> </PreferenceCategory> </PreferenceScreen>
src/com/android/settings/wifi/WifiDetailPreference.java +2 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.settings.wifi; import android.content.Context; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceViewHolder; import android.text.TextUtils; import android.util.AttributeSet; import android.widget.TextView; Loading @@ -37,6 +38,7 @@ public class WifiDetailPreference extends Preference { } public void setDetailText(String text) { if (TextUtils.equals(mDetailText, text)) return; mDetailText = text; notifyChanged(); } Loading
src/com/android/settings/wifi/details/WifiDetailPreferenceController.java +57 −59 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.graphics.drawable.Drawable; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkBadging; Loading Loading @@ -67,6 +68,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.List; import java.util.StringJoiner; import java.util.stream.Collectors; /** * Controller for logic pertaining to displaying Wifi information for the Loading Loading @@ -100,7 +102,9 @@ public class WifiDetailPreferenceController extends PreferenceController impleme @VisibleForTesting static final String KEY_DNS_PREF = "dns"; @VisibleForTesting static final String KEY_IPV6_ADDRESS_CATEGORY = "ipv6_details_category"; static final String KEY_IPV6_CATEGORY = "ipv6_category"; @VisibleForTesting static final String KEY_IPV6_ADDRESSES_PREF = "ipv6_addresses"; private AccessPoint mAccessPoint; private final ConnectivityManagerWrapper mConnectivityManagerWrapper; Loading Loading @@ -133,8 +137,9 @@ public class WifiDetailPreferenceController extends PreferenceController impleme private WifiDetailPreference mGatewayPref; private WifiDetailPreference mSubnetPref; private WifiDetailPreference mDnsPref; private PreferenceCategory mIpv6Category; private Preference mIpv6AddressPref; private PreferenceCategory mIpv6AddressCategory; private final IntentFilter mFilter; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override Loading Loading @@ -241,8 +246,8 @@ public class WifiDetailPreferenceController extends PreferenceController impleme mSubnetPref = (WifiDetailPreference) screen.findPreference(KEY_SUBNET_MASK_PREF); mDnsPref = (WifiDetailPreference) screen.findPreference(KEY_DNS_PREF); mIpv6AddressCategory = (PreferenceCategory) screen.findPreference(KEY_IPV6_ADDRESS_CATEGORY); mIpv6Category = (PreferenceCategory) screen.findPreference(KEY_IPV6_CATEGORY); mIpv6AddressPref = (Preference) screen.findPreference(KEY_IPV6_ADDRESSES_PREF); mSecurityPref.setDetailText(mAccessPoint.getSecurityString(false /* concise */)); mForgetButton = (Button) mButtonsPref.findViewById(R.id.forget_button); Loading Loading @@ -315,8 +320,6 @@ public class WifiDetailPreferenceController extends PreferenceController impleme mFrequencyPref.setDetailText(band); updateIpLayerInfo(); mButtonsPref.setVisible(mForgetButton.getVisibility() == View.VISIBLE || mSignInButton.getVisibility() == View.VISIBLE); } private void exitActivity() { Loading Loading @@ -348,74 +351,69 @@ public class WifiDetailPreferenceController extends PreferenceController impleme mSignalStrengthPref.setDetailText(mSignalStr[summarySignalLevel]); } private void updatePreference(WifiDetailPreference pref, String detailText) { if (!TextUtils.isEmpty(detailText)) { pref.setDetailText(detailText); pref.setVisible(true); } else { pref.setVisible(false); } } private void updateIpLayerInfo() { mSignInButton.setVisibility(canSignIntoNetwork() ? View.VISIBLE : View.INVISIBLE); mButtonsPref.setVisible(mForgetButton.getVisibility() == View.VISIBLE || mSignInButton.getVisibility() == View.VISIBLE); // Reset all fields mIpv6AddressCategory.removeAll(); mIpv6AddressCategory.setVisible(false); if (mNetwork == null || mLinkProperties == null) { mIpAddressPref.setVisible(false); mSubnetPref.setVisible(false); mGatewayPref.setVisible(false); mDnsPref.setVisible(false); if (mNetwork == null || mLinkProperties == null) { mIpv6Category.setVisible(false); return; } List<InetAddress> addresses = mLinkProperties.getAddresses(); // 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); pref.setSelectable(false); mIpv6AddressCategory.addPreference(pref); mIpv6AddressCategory.setVisible(true); // Find IPv4 and IPv6 addresses. String ipv4Address = null; String subnet = null; StringJoiner ipv6Addresses = new StringJoiner("\n"); for (LinkAddress addr : mLinkProperties.getLinkAddresses()) { if (addr.getAddress() instanceof Inet4Address) { ipv4Address = addr.getAddress().getHostAddress(); subnet = ipv4PrefixLengthToSubnetMask(addr.getPrefixLength()); } else if (addr.getAddress() instanceof Inet6Address) { ipv6Addresses.add(addr.getAddress().getHostAddress()); } } // Set up IPv4 gateway and subnet mask // Find IPv4 default gateway. String gateway = null; String subnet = null; for (RouteInfo routeInfo : mLinkProperties.getRoutes()) { if (routeInfo.hasGateway() && routeInfo.getGateway() instanceof Inet4Address) { if (routeInfo.isIPv4Default() && routeInfo.hasGateway()) { gateway = routeInfo.getGateway().getHostAddress(); } IpPrefix ipPrefix = routeInfo.getDestination(); if (ipPrefix != null && ipPrefix.getAddress() instanceof Inet4Address && ipPrefix.getPrefixLength() > 0) { subnet = ipv4PrefixLengthToSubnetMask(ipPrefix.getPrefixLength()); break; } } if (!TextUtils.isEmpty(subnet)) { mSubnetPref.setDetailText(subnet); mSubnetPref.setVisible(true); } // Find IPv4 DNS addresses. String dnsServers = mLinkProperties.getDnsServers().stream() .filter(Inet4Address.class::isInstance) .map(InetAddress::getHostAddress) .collect(Collectors.joining(",")); if (!TextUtils.isEmpty(gateway)) { mGatewayPref.setDetailText(gateway); mGatewayPref.setVisible(true); } // Update UI. updatePreference(mIpAddressPref, ipv4Address); updatePreference(mSubnetPref, subnet); updatePreference(mGatewayPref, gateway); updatePreference(mDnsPref, dnsServers); // Set IPv4 DNS addresses StringJoiner stringJoiner = new StringJoiner(","); for (InetAddress dnsServer : mLinkProperties.getDnsServers()) { if (dnsServer instanceof Inet4Address) { stringJoiner.add(dnsServer.getHostAddress()); } } String dnsText = stringJoiner.toString(); if (!dnsText.isEmpty()) { mDnsPref.setDetailText(dnsText); mDnsPref.setVisible(true); if (ipv6Addresses.length() > 0) { mIpv6AddressPref.setSummary(ipv6Addresses.toString()); mIpv6Category.setVisible(true); } else { mIpv6Category.setVisible(false); } } Loading
tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java +159 −44 Original line number Diff line number Diff line Loading @@ -75,9 +75,13 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) Loading @@ -89,9 +93,6 @@ public class WifiDetailPreferenceControllerTest { private static final String MAC_ADDRESS = WifiInfo.DEFAULT_MAC_ADDRESS; private static final String SECURITY = "None"; private InetAddress mIpv4Address; private Inet6Address mIpv6Address; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private PreferenceScreen mockScreen; Loading Loading @@ -120,35 +121,76 @@ public class WifiDetailPreferenceControllerTest { @Mock private WifiDetailPreference mockSubnetPref; @Mock private WifiDetailPreference mockDnsPref; @Mock private Button mockForgetButton; @Mock private PreferenceCategory mockIpv6AddressCategory; @Mock private PreferenceCategory mockIpv6Category; @Mock private WifiDetailPreference mockIpv6AddressesPref; @Captor private ArgumentCaptor<NetworkCallback> mCallbackCaptor; @Captor private ArgumentCaptor<View.OnClickListener> mForgetClickListener; @Captor private ArgumentCaptor<Preference> mIpv6AddressCaptor; private Context mContext = RuntimeEnvironment.application; private Lifecycle mLifecycle; private LinkProperties mLinkProperties; private WifiDetailPreferenceController mController; // This class exists so that these values can be made static final. They can't be static final // members of the test class, because any attempt to call IpPrefix or RouteInfo constructors // during static initialization of the test class results in NoSuchMethorError being thrown // when the test is run. private static class Constants { static final int IPV4_PREFIXLEN = 25; static final LinkAddress IPV4_ADDR; static final Inet4Address IPV4_GATEWAY; static final RouteInfo IPV4_DEFAULT; static final RouteInfo IPV4_SUBNET; static final LinkAddress IPV6_LINKLOCAL; static final LinkAddress IPV6_GLOBAL1; static final LinkAddress IPV6_GLOBAL2; static final InetAddress IPV4_DNS1; static final InetAddress IPV4_DNS2; static final InetAddress IPV6_DNS; private static LinkAddress ipv6LinkAddress(String addr) throws UnknownHostException { return new LinkAddress(InetAddress.getByName(addr), 64); } private static LinkAddress ipv4LinkAddress(String addr, int prefixlen) throws UnknownHostException { return new LinkAddress(InetAddress.getByName(addr), prefixlen); } static { try { // We create our test constants in these roundabout ways because the robolectric // shadows don't contain NetworkUtils.parseNumericAddress and other utility methods, // so the easy ways to do things fail with NoSuchMethodError. IPV4_ADDR = ipv4LinkAddress("192.0.2.2", IPV4_PREFIXLEN); IPV4_GATEWAY = (Inet4Address) InetAddress.getByName("192.0.2.127"); final Inet4Address any4 = (Inet4Address) InetAddress.getByName("0.0.0.0"); IpPrefix subnet = new IpPrefix(IPV4_ADDR.getAddress(), IPV4_PREFIXLEN); IPV4_SUBNET = new RouteInfo(subnet, any4); IPV4_DEFAULT = new RouteInfo(new IpPrefix(any4, 0), IPV4_GATEWAY); IPV6_LINKLOCAL = ipv6LinkAddress("fe80::211:25ff:fef8:7cb2%1"); IPV6_GLOBAL1 = ipv6LinkAddress("2001:db8:1::211:25ff:fef8:7cb2"); IPV6_GLOBAL2 = ipv6LinkAddress("2001:db8:1::3dfe:8902:f98f:739d"); IPV4_DNS1 = InetAddress.getByName("8.8.8.8"); IPV4_DNS2 = InetAddress.getByName("8.8.4.4"); IPV6_DNS = InetAddress.getByName("2001:4860:4860::64"); } catch (UnknownHostException e) { throw new RuntimeException("Invalid hardcoded IP addresss: " + e); } } } @Before public void setUp() { MockitoAnnotations.initMocks(this); mLifecycle = new Lifecycle(); try { mIpv4Address = InetAddress.getByAddress( new byte[] { (byte) 255, (byte) 255, (byte) 255, (byte) 255 }); mIpv6Address = Inet6Address.getByAddress( "123", /* host */ new byte[] { (byte) 0xFE, (byte) 0x80, 0, 0, 0, 0, 0, 0, 0x02, 0x11, 0x25, (byte) 0xFF, (byte) 0xFE, (byte) 0xF8, (byte) 0x7C, (byte) 0xB2}, 1 /*scope id */); } catch (UnknownHostException e) { throw new RuntimeException(e); } when(mockAccessPoint.getConfig()).thenReturn(mockWifiConfig); when(mockAccessPoint.getLevel()).thenReturn(LEVEL); when(mockAccessPoint.getSecurityString(false)).thenReturn(SECURITY); Loading Loading @@ -217,8 +259,10 @@ public class WifiDetailPreferenceControllerTest { .thenReturn(mockSubnetPref); when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_DNS_PREF)) .thenReturn(mockDnsPref); when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_IPV6_ADDRESS_CATEGORY)) .thenReturn(mockIpv6AddressCategory); when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_IPV6_CATEGORY)) .thenReturn(mockIpv6Category); when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_IPV6_ADDRESSES_PREF)) .thenReturn(mockIpv6AddressesPref); } @Test Loading Loading @@ -330,26 +374,23 @@ public class WifiDetailPreferenceControllerTest { @Test public void ipAddressPref_shouldHaveDetailTextSet() { LinkAddress ipv4Address = new LinkAddress(mIpv4Address, 32); mLinkProperties.addLinkAddress(ipv4Address); mLinkProperties.addLinkAddress(Constants.IPV4_ADDR); mController.displayPreference(mockScreen); verify(mockIpAddressPref).setDetailText(mIpv4Address.getHostAddress()); verify(mockIpAddressPref).setDetailText(Constants.IPV4_ADDR.getAddress().getHostAddress()); } @Test public void gatewayAndSubnet_shouldHaveDetailTextSet() { int prefixLength = 24; IpPrefix subnet = new IpPrefix(mIpv4Address, prefixLength); InetAddress gateway = mIpv4Address; mLinkProperties.addRoute(new RouteInfo(subnet, gateway)); mLinkProperties.addLinkAddress(Constants.IPV4_ADDR); mLinkProperties.addRoute(Constants.IPV4_DEFAULT); mLinkProperties.addRoute(Constants.IPV4_SUBNET); mController.displayPreference(mockScreen); verify(mockSubnetPref).setDetailText("255.255.255.0"); verify(mockGatewayPref).setDetailText(mIpv4Address.getHostAddress()); verify(mockSubnetPref).setDetailText("255.255.255.128"); verify(mockGatewayPref).setDetailText("192.0.2.127"); } @Test Loading @@ -376,23 +417,96 @@ public class WifiDetailPreferenceControllerTest { @Test public void noLinkProperties_allIpDetailsHidden() { when(mockConnectivityManager.getLinkProperties(mockNetwork)).thenReturn(null); reset(mockIpv6AddressCategory, mockIpAddressPref, mockSubnetPref, mockGatewayPref, reset(mockIpv6Category, mockIpAddressPref, mockSubnetPref, mockGatewayPref, mockDnsPref); mController.displayPreference(mockScreen); verify(mockIpv6AddressCategory).setVisible(false); verify(mockIpv6Category).setVisible(false); verify(mockIpAddressPref).setVisible(false); verify(mockSubnetPref).setVisible(false); verify(mockGatewayPref).setVisible(false); verify(mockDnsPref).setVisible(false); verify(mockIpv6AddressCategory, never()).setVisible(true); verify(mockIpv6Category, never()).setVisible(true); verify(mockIpAddressPref, never()).setVisible(true); verify(mockSubnetPref, never()).setVisible(true); verify(mockGatewayPref, never()).setVisible(true); verify(mockDnsPref, never()).setVisible(true); } // Convenience method to convert a LinkAddress to a string without a prefix length. private String asString(LinkAddress l) { return l.getAddress().getHostAddress(); } // Pretend that the NetworkCallback was triggered with a new copy of lp. We need to create a // new copy because the code only updates if !mLinkProperties.equals(lp). private void updateLinkProperties(LinkProperties lp) { mCallbackCaptor.getValue().onLinkPropertiesChanged(mockNetwork, new LinkProperties(lp)); } private void verifyDisplayedIpv6Addresses(InOrder inOrder, LinkAddress... addresses) { String text = Arrays.stream(addresses) .map(address -> asString(address)) .collect(Collectors.joining("\n")); inOrder.verify(mockIpv6AddressesPref).setSummary(text); } @Test public void onLinkPropertiesChanged_updatesFields() { mController.displayPreference(mockScreen); mController.onResume(); InOrder inOrder = inOrder(mockIpAddressPref, mockGatewayPref, mockSubnetPref, mockDnsPref, mockIpv6Category, mockIpv6AddressesPref); LinkProperties lp = new LinkProperties(); lp.addLinkAddress(Constants.IPV6_LINKLOCAL); updateLinkProperties(lp); verifyDisplayedIpv6Addresses(inOrder, Constants.IPV6_LINKLOCAL); inOrder.verify(mockIpv6Category).setVisible(true); lp.addRoute(Constants.IPV4_DEFAULT); updateLinkProperties(lp); inOrder.verify(mockGatewayPref).setDetailText(Constants.IPV4_GATEWAY.getHostAddress()); inOrder.verify(mockGatewayPref).setVisible(true); lp.addLinkAddress(Constants.IPV4_ADDR); lp.addRoute(Constants.IPV4_SUBNET); updateLinkProperties(lp); inOrder.verify(mockIpAddressPref).setDetailText(asString(Constants.IPV4_ADDR)); inOrder.verify(mockIpAddressPref).setVisible(true); inOrder.verify(mockSubnetPref).setDetailText("255.255.255.128"); inOrder.verify(mockSubnetPref).setVisible(true); lp.addLinkAddress(Constants.IPV6_GLOBAL1); lp.addLinkAddress(Constants.IPV6_GLOBAL2); updateLinkProperties(lp); verifyDisplayedIpv6Addresses(inOrder, Constants.IPV6_LINKLOCAL, Constants.IPV6_GLOBAL1, Constants.IPV6_GLOBAL2); lp.removeLinkAddress(Constants.IPV6_GLOBAL1); updateLinkProperties(lp); verifyDisplayedIpv6Addresses(inOrder, Constants.IPV6_LINKLOCAL, Constants.IPV6_GLOBAL2); lp.addDnsServer(Constants.IPV6_DNS); updateLinkProperties(lp); inOrder.verify(mockDnsPref, never()).setVisible(true); lp.addDnsServer(Constants.IPV4_DNS1); lp.addDnsServer(Constants.IPV4_DNS2); updateLinkProperties(lp); inOrder.verify(mockDnsPref).setDetailText( Constants.IPV4_DNS1.getHostAddress() + "," + Constants.IPV4_DNS2.getHostAddress()); inOrder.verify(mockDnsPref).setVisible(true); } @Test public void canForgetNetwork_noNetwork() { when(mockAccessPoint.getConfig()).thenReturn(null); Loading Loading @@ -496,28 +610,29 @@ public class WifiDetailPreferenceControllerTest { @Test public void ipv6AddressPref_shouldHaveHostAddressTextSet() { LinkAddress ipv6Address = new LinkAddress(mIpv6Address, 128); mLinkProperties.addLinkAddress(ipv6Address); mLinkProperties.addLinkAddress(Constants.IPV6_LINKLOCAL); mLinkProperties.addLinkAddress(Constants.IPV6_GLOBAL1); mLinkProperties.addLinkAddress(Constants.IPV6_GLOBAL2); mController.displayPreference(mockScreen); ArgumentCaptor<Preference> preferenceCaptor = ArgumentCaptor.forClass(Preference.class); verify(mockIpv6AddressCategory).addPreference(preferenceCaptor.capture()); assertThat(preferenceCaptor.getValue().getTitle()).isEqualTo(mIpv6Address.getHostAddress()); List <Preference> addrs = mIpv6AddressCaptor.getAllValues(); String expectedAddresses = String.join("\n", asString(Constants.IPV6_LINKLOCAL), asString(Constants.IPV6_GLOBAL1), asString(Constants.IPV6_GLOBAL2)); verify(mockIpv6AddressesPref).setSummary(expectedAddresses); } @Test public void ipv6AddressPref_shouldNotBeSelectable() { LinkAddress ipv6Address = new LinkAddress(mIpv6Address, 128); mLinkProperties.addLinkAddress(ipv6Address); mLinkProperties.addLinkAddress(Constants.IPV6_GLOBAL2); mController.displayPreference(mockScreen); ArgumentCaptor<Preference> preferenceCaptor = ArgumentCaptor.forClass(Preference.class); verify(mockIpv6AddressCategory).addPreference(preferenceCaptor.capture()); assertThat(preferenceCaptor.getValue().isSelectable()).isFalse(); assertThat(mockIpv6AddressesPref.isSelectable()).isFalse(); } @Test Loading