[SB Refactor] Account for underlying wifi networks in old pipeline.
This makes `WifiStatusTracker`'s logic match the logic in
`ConnectivityRepositoryImpl`.
Bug: 225902574
Test: atest WifiStatusTrackerTest
Change-Id: I01a91e38c7b07c9891a47c4cec1ca7cabcae4f49
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 45c0d78..adaf4a1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -14,7 +14,9 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
@@ -26,6 +28,8 @@
import android.net.NetworkRequest;
import android.net.NetworkScoreManager;
import android.net.ScoredNetwork;
+import android.net.TransportInfo;
+import android.net.vcn.VcnTransportInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiNetworkScoreCache;
@@ -34,8 +38,9 @@
import android.os.Looper;
import android.provider.Settings;
+import androidx.annotation.Nullable;
+
import com.android.settingslib.R;
-import com.android.settingslib.Utils;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
@@ -46,6 +51,7 @@
/**
* Track status of Wi-Fi for the Sys UI.
*/
+@SuppressLint("MissingPermission")
public class WifiStatusTracker {
private static final int HISTORY_SIZE = 32;
private static final SimpleDateFormat SSDF = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
@@ -66,8 +72,9 @@
private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder()
.clearCapabilities()
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).build();
+ .addTransportType(TRANSPORT_WIFI)
+ .addTransportType(TRANSPORT_CELLULAR)
+ .build();
private final NetworkCallback mNetworkCallback =
new NetworkCallback(NetworkCallback.FLAG_INCLUDE_LOCATION_INFO) {
// Note: onCapabilitiesChanged is guaranteed to be called "immediately" after onAvailable
@@ -75,18 +82,10 @@
@Override
public void onCapabilitiesChanged(
Network network, NetworkCapabilities networkCapabilities) {
- boolean isVcnOverWifi = false;
- boolean isWifi = false;
- WifiInfo wifiInfo = null;
- if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
- wifiInfo = Utils.tryGetWifiInfoForVcn(networkCapabilities);
- isVcnOverWifi = (wifiInfo != null);
- } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
- wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
- isWifi = true;
- }
+ WifiInfo wifiInfo = getMainOrUnderlyingWifiInfo(networkCapabilities);
+ boolean isWifi = connectionIsWifi(networkCapabilities, wifiInfo);
// As long as it is a WiFi network, we will log it in the dumpsys for debugging.
- if (isVcnOverWifi || isWifi) {
+ if (isWifi) {
String log = new StringBuilder()
.append(SSDF.format(System.currentTimeMillis())).append(",")
.append("onCapabilitiesChanged: ")
@@ -303,17 +302,8 @@
return;
}
NetworkCapabilities networkCapabilities;
- isDefaultNetwork = false;
- if (mDefaultNetworkCapabilities != null) {
- boolean isWifi = mDefaultNetworkCapabilities.hasTransport(
- NetworkCapabilities.TRANSPORT_WIFI);
- boolean isVcnOverWifi = mDefaultNetworkCapabilities.hasTransport(
- NetworkCapabilities.TRANSPORT_CELLULAR)
- && (Utils.tryGetWifiInfoForVcn(mDefaultNetworkCapabilities) != null);
- if (isWifi || isVcnOverWifi) {
- isDefaultNetwork = true;
- }
- }
+ isDefaultNetwork = mDefaultNetworkCapabilities != null
+ && connectionIsWifi(mDefaultNetworkCapabilities);
if (isDefaultNetwork) {
// Wifi is connected and the default network.
networkCapabilities = mDefaultNetworkCapabilities;
@@ -352,6 +342,70 @@
? null : AccessPoint.getSpeedLabel(mContext, scoredNetwork, rssi);
}
+ @Nullable
+ private WifiInfo getMainOrUnderlyingWifiInfo(NetworkCapabilities networkCapabilities) {
+ WifiInfo mainWifiInfo = getMainWifiInfo(networkCapabilities);
+ if (mainWifiInfo != null) {
+ return mainWifiInfo;
+ }
+
+ // Only CELLULAR networks may have underlying wifi information that's relevant to SysUI,
+ // so skip the underlying network check if it's not CELLULAR.
+ if (!networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
+ return mainWifiInfo;
+ }
+
+ List<Network> underlyingNetworks = networkCapabilities.getUnderlyingNetworks();
+ if (underlyingNetworks == null) {
+ return null;
+ }
+
+ // Some connections, like VPN connections, may have underlying networks that are
+ // eventually traced to a wifi or carrier merged connection. So, check those underlying
+ // networks for possible wifi information as well. See b/225902574.
+ for (Network underlyingNetwork : underlyingNetworks) {
+ NetworkCapabilities underlyingNetworkCapabilities =
+ mConnectivityManager.getNetworkCapabilities(underlyingNetwork);
+ WifiInfo underlyingWifiInfo = getMainWifiInfo(underlyingNetworkCapabilities);
+ if (underlyingWifiInfo != null) {
+ return underlyingWifiInfo;
+ }
+ }
+
+ return null;
+ }
+
+ @Nullable
+ private WifiInfo getMainWifiInfo(NetworkCapabilities networkCapabilities) {
+ boolean canHaveWifiInfo = networkCapabilities.hasTransport(TRANSPORT_WIFI)
+ || networkCapabilities.hasTransport(TRANSPORT_CELLULAR);
+ if (!canHaveWifiInfo) {
+ return null;
+ }
+
+ TransportInfo transportInfo = networkCapabilities.getTransportInfo();
+ if (transportInfo instanceof VcnTransportInfo) {
+ // This VcnTransportInfo logic is copied from
+ // [com.android.settingslib.Utils.tryGetWifiInfoForVcn]. It's copied instead of
+ // re-used because it makes the logic here clearer.
+ return ((VcnTransportInfo) transportInfo).getWifiInfo();
+ } else if (transportInfo instanceof WifiInfo) {
+ return (WifiInfo) transportInfo;
+ } else {
+ return null;
+ }
+ }
+
+ private boolean connectionIsWifi(NetworkCapabilities networkCapabilities) {
+ return connectionIsWifi(
+ networkCapabilities,
+ getMainOrUnderlyingWifiInfo(networkCapabilities));
+ }
+
+ private boolean connectionIsWifi(NetworkCapabilities networkCapabilities, WifiInfo wifiInfo) {
+ return wifiInfo != null || networkCapabilities.hasTransport(TRANSPORT_WIFI);
+ }
+
/** Refresh the status label on Locale changed. */
public void refreshLocale() {
updateStatusLabel();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java
index dc7e313d..6e975cf 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java
@@ -40,6 +40,8 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
+import java.util.Arrays;
+
@RunWith(RobolectricTestRunner.class)
public class WifiStatusTrackerTest {
@Mock Context mContext;
@@ -48,13 +50,32 @@
@Mock ConnectivityManager mConnectivityManager;
@Mock Runnable mCallback;
+ private WifiStatusTracker mWifiStatusTracker;
+
private final ArgumentCaptor<ConnectivityManager.NetworkCallback>
mNetworkCallbackCaptor =
ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
+ private final ArgumentCaptor<ConnectivityManager.NetworkCallback>
+ mDefaultNetworkCallbackCaptor =
+ ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+
+ mWifiStatusTracker = new WifiStatusTracker(
+ mContext,
+ mWifiManager,
+ mNetworkScoreManager,
+ mConnectivityManager,
+ mCallback);
+ mWifiStatusTracker.setListening(true);
+
+ verify(mConnectivityManager)
+ .registerNetworkCallback(any(), mNetworkCallbackCaptor.capture(), any());
+ verify(mConnectivityManager)
+ .registerDefaultNetworkCallback(mDefaultNetworkCallbackCaptor.capture(), any());
}
/**
@@ -62,13 +83,6 @@
*/
@Test
public void testWifiInfoClearedOnPrimaryNetworkLost() {
- WifiStatusTracker wifiStatusTracker = new WifiStatusTracker(mContext, mWifiManager,
- mNetworkScoreManager, mConnectivityManager, mCallback);
- wifiStatusTracker.setListening(true);
-
- verify(mConnectivityManager)
- .registerNetworkCallback(any(), mNetworkCallbackCaptor.capture(), any());
-
// Trigger a validation callback for the primary Wifi network.
WifiInfo primaryWifiInfo = Mockito.mock(WifiInfo.class);
when(primaryWifiInfo.makeCopy(anyLong())).thenReturn(primaryWifiInfo);
@@ -86,8 +100,8 @@
mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap);
// Verify primary wifi info is the one being used.
- assertThat(wifiStatusTracker.connected).isTrue();
- assertThat(wifiStatusTracker.rssi).isEqualTo(primaryRssi);
+ assertThat(mWifiStatusTracker.connected).isTrue();
+ assertThat(mWifiStatusTracker.rssi).isEqualTo(primaryRssi);
// Trigger a validation callback for the non-primary Wifi network.
WifiInfo nonPrimaryWifiInfo = Mockito.mock(WifiInfo.class);
@@ -106,20 +120,189 @@
mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(nonPrimaryNetwork, nonPrimaryCap);
// Verify primary wifi info is still the one being used.
- assertThat(wifiStatusTracker.connected).isTrue();
- assertThat(wifiStatusTracker.rssi).isEqualTo(primaryRssi);
+ assertThat(mWifiStatusTracker.connected).isTrue();
+ assertThat(mWifiStatusTracker.rssi).isEqualTo(primaryRssi);
// Lose the non-primary network.
mNetworkCallbackCaptor.getValue().onLost(nonPrimaryNetwork);
// Verify primary wifi info is still the one being used.
- assertThat(wifiStatusTracker.connected).isTrue();
- assertThat(wifiStatusTracker.rssi).isEqualTo(primaryRssi);
+ assertThat(mWifiStatusTracker.connected).isTrue();
+ assertThat(mWifiStatusTracker.rssi).isEqualTo(primaryRssi);
// Lose the primary network.
mNetworkCallbackCaptor.getValue().onLost(primaryNetwork);
// Verify we aren't connected anymore.
- assertThat(wifiStatusTracker.connected).isFalse();
+ assertThat(mWifiStatusTracker.connected).isFalse();
+ }
+
+ @Test
+ public void isCarrierMerged_typicalWifi_false() {
+ WifiInfo primaryWifiInfo = Mockito.mock(WifiInfo.class);
+ when(primaryWifiInfo.isPrimary()).thenReturn(true);
+
+ NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class);
+ when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)).thenReturn(true);
+ when(primaryCap.getTransportInfo()).thenReturn(primaryWifiInfo);
+
+ Network primaryNetwork = Mockito.mock(Network.class);
+ int primaryNetworkId = 1;
+ when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId);
+
+ mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap);
+
+ assertThat(mWifiStatusTracker.isCarrierMerged).isFalse();
+ }
+
+ @Test
+ public void isCarrierMerged_typicalCellular_false() {
+ NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class);
+ when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).thenReturn(true);
+
+ Network primaryNetwork = Mockito.mock(Network.class);
+ int primaryNetworkId = 1;
+ when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId);
+
+ mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap);
+
+ assertThat(mWifiStatusTracker.isCarrierMerged).isFalse();
+ }
+
+ @Test
+ public void isCarrierMerged_cellularCarrierMergedWifi_true() {
+ WifiInfo primaryWifiInfo = Mockito.mock(WifiInfo.class);
+ when(primaryWifiInfo.isPrimary()).thenReturn(true);
+ when(primaryWifiInfo.isCarrierMerged()).thenReturn(true);
+
+ NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class);
+ when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).thenReturn(true);
+ when(primaryCap.getTransportInfo()).thenReturn(primaryWifiInfo);
+
+ Network primaryNetwork = Mockito.mock(Network.class);
+ int primaryNetworkId = 1;
+ when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId);
+
+ mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap);
+
+ assertThat(mWifiStatusTracker.isCarrierMerged).isTrue();
+ }
+
+ /** Test for b/225902574. */
+ @Test
+ public void isCarrierMerged_cellularWithUnderlyingCarrierMergedWifi_true() {
+ WifiInfo underlyingCarrierMergedInfo = Mockito.mock(WifiInfo.class);
+ when(underlyingCarrierMergedInfo.isPrimary()).thenReturn(true);
+ when(underlyingCarrierMergedInfo.isCarrierMerged()).thenReturn(true);
+
+ NetworkCapabilities underlyingNetworkCapabilities = Mockito.mock(NetworkCapabilities.class);
+ when(underlyingNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR))
+ .thenReturn(true);
+ when(underlyingNetworkCapabilities.getTransportInfo())
+ .thenReturn(underlyingCarrierMergedInfo);
+
+ Network underlyingNetwork = Mockito.mock(Network.class);
+ when(mConnectivityManager.getNetworkCapabilities(underlyingNetwork))
+ .thenReturn(underlyingNetworkCapabilities);
+
+ NetworkCapabilities mainCapabilities = Mockito.mock(NetworkCapabilities.class);
+ when(mainCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR))
+ .thenReturn(true);
+ when(mainCapabilities.getTransportInfo()).thenReturn(null);
+ when(mainCapabilities.getUnderlyingNetworks())
+ .thenReturn(Arrays.asList(underlyingNetwork));
+
+ Network primaryNetwork = Mockito.mock(Network.class);
+ int primaryNetworkId = 1;
+ when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId);
+
+ mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, mainCapabilities);
+
+ assertThat(mWifiStatusTracker.isCarrierMerged).isTrue();
+ }
+
+ @Test
+ public void isDefaultNetwork_typicalWifi_true() {
+ WifiInfo primaryWifiInfo = Mockito.mock(WifiInfo.class);
+ when(primaryWifiInfo.isPrimary()).thenReturn(true);
+
+ NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class);
+ when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)).thenReturn(true);
+ when(primaryCap.getTransportInfo()).thenReturn(primaryWifiInfo);
+
+ Network primaryNetwork = Mockito.mock(Network.class);
+ int primaryNetworkId = 1;
+ when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId);
+
+ mDefaultNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap);
+
+ assertThat(mWifiStatusTracker.isDefaultNetwork).isTrue();
+ }
+
+ @Test
+ public void isDefaultNetwork_typicalCellular_false() {
+ NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class);
+ when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).thenReturn(true);
+
+ Network primaryNetwork = Mockito.mock(Network.class);
+ int primaryNetworkId = 1;
+ when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId);
+
+ mDefaultNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap);
+
+ assertThat(mWifiStatusTracker.isDefaultNetwork).isFalse();
+ }
+
+ @Test
+ public void isDefaultNetwork_cellularCarrierMergedWifi_true() {
+ WifiInfo primaryWifiInfo = Mockito.mock(WifiInfo.class);
+ when(primaryWifiInfo.isPrimary()).thenReturn(true);
+ when(primaryWifiInfo.isCarrierMerged()).thenReturn(true);
+
+ NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class);
+ when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).thenReturn(true);
+ when(primaryCap.getTransportInfo()).thenReturn(primaryWifiInfo);
+
+ Network primaryNetwork = Mockito.mock(Network.class);
+ int primaryNetworkId = 1;
+ when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId);
+
+ mDefaultNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap);
+
+ assertThat(mWifiStatusTracker.isDefaultNetwork).isTrue();
+ }
+
+ /** Test for b/225902574. */
+ @Test
+ public void isDefaultNetwork_cellularWithUnderlyingCarrierMergedWifi_true() {
+ WifiInfo underlyingCarrierMergedInfo = Mockito.mock(WifiInfo.class);
+ when(underlyingCarrierMergedInfo.isPrimary()).thenReturn(true);
+ when(underlyingCarrierMergedInfo.isCarrierMerged()).thenReturn(true);
+
+ NetworkCapabilities underlyingNetworkCapabilities = Mockito.mock(NetworkCapabilities.class);
+ when(underlyingNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR))
+ .thenReturn(true);
+ when(underlyingNetworkCapabilities.getTransportInfo())
+ .thenReturn(underlyingCarrierMergedInfo);
+
+ Network underlyingNetwork = Mockito.mock(Network.class);
+ when(mConnectivityManager.getNetworkCapabilities(underlyingNetwork))
+ .thenReturn(underlyingNetworkCapabilities);
+
+ NetworkCapabilities mainCapabilities = Mockito.mock(NetworkCapabilities.class);
+ when(mainCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR))
+ .thenReturn(true);
+ when(mainCapabilities.getTransportInfo()).thenReturn(null);
+ when(mainCapabilities.getUnderlyingNetworks())
+ .thenReturn(Arrays.asList(underlyingNetwork));
+
+ Network primaryNetwork = Mockito.mock(Network.class);
+ int primaryNetworkId = 1;
+ when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId);
+
+ mDefaultNetworkCallbackCaptor.getValue()
+ .onCapabilitiesChanged(primaryNetwork, mainCapabilities);
+
+ assertThat(mWifiStatusTracker.isDefaultNetwork).isTrue();
}
}