diff --git a/res/xml/wifi_network_details_fragment.xml b/res/xml/wifi_network_details_fragment.xml
index 5b20d595daf..5d5958d534e 100644
--- a/res/xml/wifi_network_details_fragment.xml
+++ b/res/xml/wifi_network_details_fragment.xml
@@ -28,9 +28,9 @@
android:key="general_details_category" >
+ android:key="buttons"
+ android:layout="@layout/two_buttons_panel"
+ android:selectable="false" />
mConnectivityManagerWrapper.startCaptivePortalApp(mNetwork));
+
mSignalStrengthPref =
(WifiDetailPreference) screen.findPreference(KEY_SIGNAL_STRENGTH_PREF);
mLinkSpeedPref = (WifiDetailPreference) screen.findPreference(KEY_LINK_SPEED);
@@ -191,6 +249,12 @@ public class WifiDetailPreferenceController extends PreferenceController impleme
@Override
public void onResume() {
+ mConnectivityManagerWrapper.registerNetworkCallback(mNetworkRequest, mNetworkCallback,
+ mHandler);
+ mNetwork = mWifiManager.getCurrentNetwork();
+ mLinkProperties = mConnectivityManager.getLinkProperties(mNetwork);
+ mNetworkCapabilities = mConnectivityManager.getNetworkCapabilities(mNetwork);
+
updateInfo();
mContext.registerReceiver(mReceiver, mFilter);
@@ -198,13 +262,17 @@ public class WifiDetailPreferenceController extends PreferenceController impleme
@Override
public void onPause() {
+ mNetwork = null;
+ mLinkProperties = null;
+ mNetworkCapabilities = null;
mContext.unregisterReceiver(mReceiver);
+ mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
}
private void updateInfo() {
- mNetworkInfo = mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());
+ mNetworkInfo = mConnectivityManager.getNetworkInfo(mNetwork);
mWifiInfo = mWifiManager.getConnectionInfo();
- if (mNetworkInfo == null || mWifiInfo == null) {
+ if (mNetwork == null || mNetworkInfo == null || mWifiInfo == null) {
exitActivity();
return;
}
@@ -238,7 +306,7 @@ public class WifiDetailPreferenceController extends PreferenceController impleme
}
mFrequencyPref.setDetailText(band);
- setIpText();
+ updateIpLayerInfo();
}
private void exitActivity() {
@@ -270,7 +338,9 @@ public class WifiDetailPreferenceController extends PreferenceController impleme
mSignalStrengthPref.setDetailText(mSignalStr[summarySignalLevel]);
}
- private void setIpText() {
+ private void updateIpLayerInfo() {
+ mSignInButton.setVisibility(canSignIntoNetwork() ? View.VISIBLE : View.INVISIBLE);
+
// Reset all fields
mIpv6AddressCategory.removeAll();
mIpv6AddressCategory.setVisible(false);
@@ -279,18 +349,12 @@ public class WifiDetailPreferenceController extends PreferenceController impleme
mGatewayPref.setVisible(false);
mDnsPref.setVisible(false);
- Network currentNetwork = mWifiManager.getCurrentNetwork();
- if (currentNetwork == null) {
+ if (mNetwork == null || mLinkProperties == null) {
return;
}
+ List addresses = mLinkProperties.getAddresses();
- LinkProperties linkProperties = mConnectivityManager.getLinkProperties(currentNetwork);
- if (linkProperties == null) {
- return;
- }
- List addresses = linkProperties.getAddresses();
-
- // Set IPv4 and Ipv6 addresses
+ // Set IPv4 and IPv6 addresses
for (int i = 0; i < addresses.size(); i++) {
InetAddress addr = addresses.get(i);
if (addr instanceof Inet4Address) {
@@ -310,7 +374,7 @@ public class WifiDetailPreferenceController extends PreferenceController impleme
// Set up IPv4 gateway and subnet mask
String gateway = null;
String subnet = null;
- for (RouteInfo routeInfo : linkProperties.getRoutes()) {
+ for (RouteInfo routeInfo : mLinkProperties.getRoutes()) {
if (routeInfo.hasGateway() && routeInfo.getGateway() instanceof Inet4Address) {
gateway = routeInfo.getGateway().getHostAddress();
}
@@ -333,7 +397,7 @@ public class WifiDetailPreferenceController extends PreferenceController impleme
// Set IPv4 DNS addresses
StringJoiner stringJoiner = new StringJoiner(",");
- for (InetAddress dnsServer : linkProperties.getDnsServers()) {
+ for (InetAddress dnsServer : mLinkProperties.getDnsServers()) {
if (dnsServer instanceof Inet4Address) {
stringJoiner.add(dnsServer.getHostAddress());
}
@@ -362,6 +426,14 @@ public class WifiDetailPreferenceController extends PreferenceController impleme
return mWifiInfo != null && mWifiInfo.isEphemeral() || mWifiConfig != null;
}
+ /**
+ * Returns whether the user can sign into the network represented by this preference.
+ */
+ private boolean canSignIntoNetwork() {
+ return mNetworkCapabilities != null && mNetworkCapabilities.hasCapability(
+ NET_CAPABILITY_CAPTIVE_PORTAL);
+ }
+
/**
* Forgets the wifi network associated with this preference.
*/
diff --git a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
index adcfcc0b3ab..fe16cdb0306 100644
--- a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
+++ b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
@@ -17,8 +17,12 @@ package com.android.settings.wifi.details;
import android.content.Context;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.NetworkRequest;
import android.net.wifi.WifiManager;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.widget.Button;
import com.android.internal.logging.nano.MetricsProto;
@@ -26,6 +30,7 @@ import com.android.settings.R;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.core.PreferenceController;
import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.vpn2.ConnectivityManagerWrapperImpl;
import com.android.settingslib.wifi.AccessPoint;
import java.util.ArrayList;
@@ -40,9 +45,6 @@ import java.util.List;
public class WifiNetworkDetailsFragment extends DashboardFragment {
private static final String TAG = "WifiNetworkDetailsFrg";
- // XML KEYS
- private static final String KEY_FORGET_BUTTON = "forget_button";
-
private AccessPoint mAccessPoint;
private Button mForgetButton;
private WifiDetailPreferenceController mWifiDetailPreferenceController;
@@ -59,9 +61,11 @@ public class WifiNetworkDetailsFragment extends DashboardFragment {
// Header Title set automatically from launching Preference
- LayoutPreference forgetPreference = ((LayoutPreference) findPreference(KEY_FORGET_BUTTON));
- forgetPreference.setVisible(mWifiDetailPreferenceController.canForgetNetwork());
- mForgetButton = (Button) forgetPreference.findViewById(R.id.button);
+ LayoutPreference buttonsPreference = ((LayoutPreference) findPreference(
+ WifiDetailPreferenceController.KEY_BUTTONS_PREF));
+ buttonsPreference.setVisible(mWifiDetailPreferenceController.canForgetNetwork());
+
+ mForgetButton = (Button) buttonsPreference.findViewById(R.id.left_button);
mForgetButton.setText(R.string.forget);
mForgetButton.setOnClickListener(view -> forgetNetwork());
}
@@ -88,11 +92,13 @@ public class WifiNetworkDetailsFragment extends DashboardFragment {
@Override
protected List getPreferenceControllers(Context context) {
+ ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
mWifiDetailPreferenceController = new WifiDetailPreferenceController(
mAccessPoint,
- context.getSystemService(ConnectivityManager.class),
+ new ConnectivityManagerWrapperImpl(cm),
context,
this,
+ new Handler(Looper.getMainLooper()), // UI thread.
getLifecycle(),
context.getSystemService(WifiManager.class));
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 8d28dee82b3..b9dde37f3fc 100644
--- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
@@ -18,6 +18,8 @@ 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.doNothing;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
@@ -29,25 +31,35 @@ import android.content.Context;
import android.content.Intent;
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;
+import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
+import android.net.NetworkRequest;
import android.net.RouteInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
+import android.os.Handler;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
import com.android.settings.R;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
+import com.android.settings.applications.LayoutPreference;
import com.android.settings.core.lifecycle.Lifecycle;
import com.android.settings.wifi.WifiDetailPreference;
+import com.android.settings.vpn2.ConnectivityManagerWrapper;
+import com.android.settings.vpn2.ConnectivityManagerWrapperImpl;
import com.android.settingslib.wifi.AccessPoint;
import org.junit.Before;
@@ -55,6 +67,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
@@ -83,6 +96,7 @@ public class WifiDetailPreferenceControllerTest {
@Mock private AccessPoint mockAccessPoint;
@Mock private Activity mockActivity;
@Mock private ConnectivityManager mockConnectivityManager;
+ @Mock private ConnectivityManagerWrapperImpl mockConnectivityManagerWrapper;
@Mock private Network mockNetwork;
@Mock private NetworkInfo mockNetworkInfo;
@Mock private WifiConfiguration mockWifiConfig;
@@ -91,6 +105,8 @@ public class WifiDetailPreferenceControllerTest {
@Mock private WifiManager mockWifiManager;
@Mock private Preference mockConnectionDetailPref;
+ @Mock private LayoutPreference mockButtonsPref;
+ @Mock private Button mockSignInButton;
@Mock private WifiDetailPreference mockSignalStrengthPref;
@Mock private WifiDetailPreference mockLinkSpeedPref;
@Mock private WifiDetailPreference mockFrequencyPref;
@@ -102,9 +118,10 @@ public class WifiDetailPreferenceControllerTest {
@Mock private WifiDetailPreference mockDnsPref;
@Mock private PreferenceCategory mockIpv6AddressCategory;
- private LinkProperties mLinkProperties;
+ private ArgumentCaptor mCallbackCaptor;
private Context mContext = RuntimeEnvironment.application;
private Lifecycle mLifecycle;
+ private LinkProperties mLinkProperties;
private WifiDetailPreferenceController mController;
@Before
@@ -126,14 +143,20 @@ public class WifiDetailPreferenceControllerTest {
throw new RuntimeException(e);
}
+ mCallbackCaptor = ArgumentCaptor.forClass(NetworkCallback.class);
+
when(mockAccessPoint.getConfig()).thenReturn(mockWifiConfig);
when(mockAccessPoint.getLevel()).thenReturn(LEVEL);
when(mockAccessPoint.getNetworkInfo()).thenReturn(mockNetworkInfo);
when(mockAccessPoint.getRssi()).thenReturn(RSSI);
when(mockAccessPoint.getSecurityString(false)).thenReturn(SECURITY);
+ when(mockConnectivityManagerWrapper.getConnectivityManager())
+ .thenReturn(mockConnectivityManager);
when(mockConnectivityManager.getNetworkInfo(any(Network.class)))
.thenReturn(mockNetworkInfo);
+ doNothing().when(mockConnectivityManagerWrapper).registerNetworkCallback(
+ any(NetworkRequest.class), mCallbackCaptor.capture(), any(Handler.class));
when(mockWifiInfo.getLinkSpeed()).thenReturn(LINK_SPEED);
when(mockWifiInfo.getRssi()).thenReturn(RSSI);
@@ -154,9 +177,10 @@ public class WifiDetailPreferenceControllerTest {
private WifiDetailPreferenceController newWifiDetailPreferenceController() {
return new WifiDetailPreferenceController(
mockAccessPoint,
- mockConnectivityManager,
+ mockConnectivityManagerWrapper,
mContext,
mockFragment,
+ null, // Handler
mLifecycle,
mockWifiManager);
}
@@ -166,6 +190,10 @@ public class WifiDetailPreferenceControllerTest {
when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_CONNECTION_DETAIL_PREF))
.thenReturn(mockConnectionDetailPref);
+ when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_BUTTONS_PREF))
+ .thenReturn(mockButtonsPref);
+ when(mockButtonsPref.findViewById(R.id.right_button))
+ .thenReturn(mockSignInButton);
when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_SIGNAL_STRENGTH_PREF))
.thenReturn(mockSignalStrengthPref);
when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_LINK_SPEED))
@@ -214,6 +242,23 @@ public class WifiDetailPreferenceControllerTest {
verify(mockConnectivityManager, times(1)).getNetworkInfo(any(Network.class));
}
+ @Test
+ public void networkCallback_shouldBeRegisteredOnResume() {
+ mController.onResume();
+
+ verify(mockConnectivityManagerWrapper, times(1)).registerNetworkCallback(
+ any(NetworkRequest.class), mCallbackCaptor.capture(), any(Handler.class));
+ }
+
+ @Test
+ public void networkCallback_shouldBeUnregisteredOnPause() {
+ mController.onResume();
+ mController.onPause();
+
+ verify(mockConnectivityManager, times(1)).unregisterNetworkCallback(
+ mCallbackCaptor.getValue());
+ }
+
@Test
public void connectionDetailPref_shouldHaveIconSet() {
Drawable expectedIcon =
@@ -311,23 +356,14 @@ public class WifiDetailPreferenceControllerTest {
}
@Test
- public void noCurrentNetwork_allIpDetailsHidden() {
+ public void noCurrentNetwork_shouldFinishActivity() {
+ // If WifiManager#getCurrentNetwork() returns null, then the network is neither connected
+ // nor connecting and WifiStateMachine has not reached L2ConnectedState.
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);
+ verify(mockActivity).finish();
}
@Test
@@ -432,6 +468,15 @@ public class WifiDetailPreferenceControllerTest {
verify(mockActivity).finish();
}
+ @Test
+ public void networkOnLost_shouldFinishActivity() {
+ mController.onResume();
+
+ mCallbackCaptor.getValue().onLost(mockNetwork);
+
+ verify(mockActivity).finish();
+ }
+
@Test
public void ipv6AddressPref_shouldHaveHostAddressTextSet() {
LinkAddress ipv6Address = new LinkAddress(mIpv6Address, 128);
@@ -457,4 +502,40 @@ public class WifiDetailPreferenceControllerTest {
verify(mockIpv6AddressCategory).addPreference(preferenceCaptor.capture());
assertThat(preferenceCaptor.getValue().isSelectable()).isFalse();
}
+
+ @Test
+ public void captivePortal_shouldShowSignInButton() {
+ reset(mockSignInButton);
+ InOrder inOrder = inOrder(mockSignInButton);
+ mController.onResume();
+ inOrder.verify(mockSignInButton).setVisibility(View.INVISIBLE);
+
+ NetworkCapabilities nc = new NetworkCapabilities();
+ nc.clearAll();
+ nc.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+
+ NetworkCallback callback = mCallbackCaptor.getValue();
+ callback.onCapabilitiesChanged(mockNetwork, nc);
+ inOrder.verify(mockSignInButton).setVisibility(View.INVISIBLE);
+
+ nc = new NetworkCapabilities(nc);
+ nc.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
+ callback.onCapabilitiesChanged(mockNetwork, nc);
+ inOrder.verify(mockSignInButton).setVisibility(View.VISIBLE);
+
+ nc = new NetworkCapabilities(nc);
+ nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
+ callback.onCapabilitiesChanged(mockNetwork, nc);
+ inOrder.verify(mockSignInButton).setVisibility(View.INVISIBLE);
+ }
+
+ @Test
+ public void testSignInButton_shouldStartCaptivePortalApp() {
+ mController.onResume();
+
+ ArgumentCaptor captor = ArgumentCaptor.forClass(OnClickListener.class);
+ verify(mockSignInButton).setOnClickListener(captor.capture());
+ captor.getValue().onClick(mockSignInButton);
+ verify(mockConnectivityManagerWrapper).startCaptivePortalApp(mockNetwork);
+ }
}