diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java index fc47f705b4c..2de8d9f2c63 100644 --- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java +++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java @@ -16,6 +16,7 @@ package com.android.settings.wifi.details; import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL; +import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import android.app.Fragment; @@ -165,9 +166,24 @@ public class WifiDetailPreferenceController extends PreferenceController impleme } } + private boolean hasCapabilityChanged(NetworkCapabilities nc, int cap) { + // If this is the first time we get NetworkCapabilities, report that something changed. + if (mNetworkCapabilities == null) return true; + + // nc can never be null, see ConnectivityService#callCallbackForRequest. + return mNetworkCapabilities.hasCapability(cap) != nc.hasCapability(cap); + } + @Override public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { + // If the network just validated or lost Internet access, refresh network state. + // Don't do this on every NetworkCapabilities change because refreshNetworkState + // sends IPCs to the system server from the UI thread, which can cause jank. if (network.equals(mNetwork) && !nc.equals(mNetworkCapabilities)) { + if (hasCapabilityChanged(nc, NET_CAPABILITY_VALIDATED) || + hasCapabilityChanged(nc, NET_CAPABILITY_CAPTIVE_PORTAL)) { + refreshNetworkState(); + } mNetworkCapabilities = nc; updateIpLayerInfo(); } 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 1811b6315a0..17da8da17b8 100644 --- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java @@ -446,6 +446,17 @@ public class WifiDetailPreferenceControllerTest { mCallbackCaptor.getValue().onLinkPropertiesChanged(mockNetwork, new LinkProperties(lp)); } + private void updateNetworkCapabilities(NetworkCapabilities nc) { + mCallbackCaptor.getValue().onCapabilitiesChanged(mockNetwork, new NetworkCapabilities(nc)); + } + + private NetworkCapabilities makeNetworkCapabilities() { + NetworkCapabilities nc = new NetworkCapabilities(); + nc.clearAll(); + nc.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); + return nc; + } + private void verifyDisplayedIpv6Addresses(InOrder inOrder, LinkAddress... addresses) { String text = Arrays.stream(addresses) .map(address -> asString(address)) @@ -508,6 +519,45 @@ public class WifiDetailPreferenceControllerTest { inOrder.verify(mockDnsPref).setVisible(true); } + @Test + public void onCapabilitiesChanged_callsRefreshIfNecessary() { + NetworkCapabilities nc = makeNetworkCapabilities(); + when(mockConnectivityManager.getNetworkCapabilities(mockNetwork)) + .thenReturn(new NetworkCapabilities(nc)); + + String summary = "Connected, no Internet"; + when(mockAccessPoint.getSettingsSummary()).thenReturn(summary); + + InOrder inOrder = inOrder(mockConnectionDetailPref); + mController.displayPreference(mockScreen); + mController.onResume(); + inOrder.verify(mockConnectionDetailPref).setTitle(summary); + + // Check that an irrelevant capability update does not update the access point summary, as + // doing so could cause unnecessary jank... + summary = "Connected"; + when(mockAccessPoint.getSettingsSummary()).thenReturn(summary); + updateNetworkCapabilities(nc); + inOrder.verify(mockConnectionDetailPref, never()).setTitle(any()); + + // ... but that if the network validates, then we do refresh. + nc.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); + updateNetworkCapabilities(nc); + inOrder.verify(mockConnectionDetailPref).setTitle(summary); + + summary = "Connected, no Internet"; + when(mockAccessPoint.getSettingsSummary()).thenReturn(summary); + + // Another irrelevant update won't cause the UI to refresh... + updateNetworkCapabilities(nc); + inOrder.verify(mockConnectionDetailPref, never()).setTitle(any()); + + // ... but if the network is no longer validated, then we display "connected, no Internet". + nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); + updateNetworkCapabilities(nc); + inOrder.verify(mockConnectionDetailPref).setTitle(summary); + } + @Test public void canForgetNetwork_noNetwork() { when(mockAccessPoint.getConfig()).thenReturn(null); @@ -590,7 +640,7 @@ public class WifiDetailPreferenceControllerTest { } @Test - public void networkDisconnectdState_shouldFinishActivity() { + public void networkDisconnectedState_shouldFinishActivity() { mController.onResume(); when(mockConnectivityManager.getNetworkInfo(any(Network.class))).thenReturn(null); @@ -645,22 +695,16 @@ public class WifiDetailPreferenceControllerTest { 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); + NetworkCapabilities nc = makeNetworkCapabilities(); + updateNetworkCapabilities(nc); inOrder.verify(mockSignInButton).setVisibility(View.INVISIBLE); - nc = new NetworkCapabilities(nc); nc.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL); - callback.onCapabilitiesChanged(mockNetwork, nc); + updateNetworkCapabilities(nc); inOrder.verify(mockSignInButton).setVisibility(View.VISIBLE); - nc = new NetworkCapabilities(nc); nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL); - callback.onCapabilitiesChanged(mockNetwork, nc); + updateNetworkCapabilities(nc); inOrder.verify(mockSignInButton).setVisibility(View.INVISIBLE); }