diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java index 12f2c22ab86a9..f84b96c94a91b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java @@ -15,13 +15,14 @@ */ package com.android.systemui.statusbar.connectivity; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN; import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT; import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT; import android.content.Context; import android.content.Intent; -import android.net.NetworkCapabilities; import android.net.wifi.WifiManager; import android.os.Handler; import android.text.Html; @@ -37,6 +38,7 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Background; import java.io.PrintWriter; +import java.util.BitSet; /** */ public class WifiSignalController extends SignalController { @@ -56,8 +58,12 @@ public class WifiSignalController extends SignalController WifiManager wifiManager, WifiStatusTrackerFactory trackerFactory, @Background Handler bgHandler) { - super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI, - callbackHandler, networkController); + super( + "WifiSignalController", + context, + TRANSPORT_WIFI, + callbackHandler, + networkController); mBgHandler = bgHandler; mWifiManager = wifiManager; mWifiTracker = trackerFactory.createTracker(this::handleStatusUpdated, bgHandler); @@ -160,7 +166,10 @@ public class WifiSignalController extends SignalController // The WiFi signal level returned by WifiManager#calculateSignalLevel start from 0, so // WifiManager#getMaxSignalLevel + 1 represents the total level buckets count. int totalLevel = mWifiManager.getMaxSignalLevel() + 1; - boolean noInternet = mCurrentState.inetCondition == 0; + // A carrier merged connection could come from a WIFI *or* CELLULAR transport, so we can't + // use [mCurrentState.inetCondition], which only checks the WIFI status. Instead, check if + // the default connection is validated at all. + boolean noInternet = !mCurrentState.isDefaultConnectionValidated; if (mCurrentState.connected) { return SignalDrawable.getState(level, totalLevel, noInternet); } else if (mCurrentState.enabled) { @@ -236,6 +245,18 @@ public class WifiSignalController extends SignalController && mCurrentState.isCarrierMerged && (mCurrentState.subId == subId); } + @Override + void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) { + mCurrentState.inetCondition = validatedTransports.get(mTransportType) ? 1 : 0; + // Because a carrier merged connection can come from either a CELLULAR *or* WIFI transport, + // we need to also store if either transport is validated to correctly display the carrier + // merged case. + mCurrentState.isDefaultConnectionValidated = + validatedTransports.get(TRANSPORT_CELLULAR) + || validatedTransports.get(TRANSPORT_WIFI); + notifyListenersIfNecessary(); + } + @VisibleForTesting void setActivity(int wifiActivity) { mCurrentState.activityIn = wifiActivity == DATA_ACTIVITY_INOUT diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiState.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiState.kt index d32e34915c612..63a63de83d716 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiState.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiState.kt @@ -24,6 +24,14 @@ internal class WifiState( @JvmField var isDefault: Boolean = false, @JvmField var statusLabel: String? = null, @JvmField var isCarrierMerged: Boolean = false, + /** + * True if the current default connection is validated for *any* transport, not just wifi. + * (Specifically TRANSPORT_CELLULAR *or* TRANSPORT_WIFI.) + * + * This should *only* be used when calculating information for the carrier merged connection and + * *not* for typical wifi connections. See b/225902574. + */ + @JvmField var isDefaultConnectionValidated: Boolean = false, @JvmField var subId: Int = 0 ) : ConnectivityState() { @@ -35,6 +43,7 @@ internal class WifiState( isDefault = state.isDefault statusLabel = state.statusLabel isCarrierMerged = state.isCarrierMerged + isDefaultConnectionValidated = state.isDefaultConnectionValidated subId = state.subId } @@ -45,6 +54,7 @@ internal class WifiState( .append(",isDefault=").append(isDefault) .append(",statusLabel=").append(statusLabel) .append(",isCarrierMerged=").append(isCarrierMerged) + .append(",isDefaultConnectionValidated=").append(isDefaultConnectionValidated) .append(",subId=").append(subId) } @@ -54,6 +64,7 @@ internal class WifiState( "isDefault", "statusLabel", "isCarrierMerged", + "isDefaultConnectionValidated", "subId") return super.tableColumns() + columns @@ -65,6 +76,7 @@ internal class WifiState( isDefault, statusLabel, isCarrierMerged, + isDefaultConnectionValidated, subId).map { it.toString() } @@ -84,6 +96,7 @@ internal class WifiState( if (isDefault != other.isDefault) return false if (statusLabel != other.statusLabel) return false if (isCarrierMerged != other.isCarrierMerged) return false + if (isDefaultConnectionValidated != other.isDefaultConnectionValidated) return false if (subId != other.subId) return false return true @@ -96,6 +109,7 @@ internal class WifiState( result = 31 * result + isDefault.hashCode() result = 31 * result + (statusLabel?.hashCode() ?: 0) result = 31 * result + isCarrierMerged.hashCode() + result = 31 * result + isDefaultConnectionValidated.hashCode() result = 31 * result + subId return result } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java index c7ea09cb519dd..2e5afa4a8b500 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java @@ -339,6 +339,11 @@ public class NetworkControllerBaseTest extends SysuiTestCase { mock(Network.class), builder.build()); } + public void setConnectivityViaCallbackInNetworkController( + Network network, NetworkCapabilities networkCapabilities) { + mDefaultCallbackInNetworkController.onCapabilitiesChanged(network, networkCapabilities); + } + public void setConnectivityViaCallbackInNetworkController( int networkType, boolean validated, boolean isConnected, WifiInfo wifiInfo) { final NetworkCapabilities.Builder builder = @@ -351,6 +356,13 @@ public class NetworkControllerBaseTest extends SysuiTestCase { mock(Network.class), builder.build()); } + public void setConnectivityViaDefaultAndNormalCallbackInWifiTracker( + Network network, NetworkCapabilities networkCapabilities) { + mNetworkCallback.onAvailable(network); + mNetworkCallback.onCapabilitiesChanged(network, networkCapabilities); + mDefaultCallbackInWifiTracker.onCapabilitiesChanged(network, networkCapabilities); + } + public void setConnectivityViaCallbackInWifiTracker( int networkType, boolean validated, boolean isConnected, WifiInfo wifiInfo) { final NetworkCapabilities.Builder builder = diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java index 68170ea4b518e..44a1c50e5a585 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java @@ -16,6 +16,9 @@ package com.android.systemui.statusbar.connectivity; +import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; + import static junit.framework.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -25,6 +28,7 @@ import static org.mockito.Mockito.when; import android.content.Intent; import android.net.ConnectivityManager; +import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.vcn.VcnTransportInfo; @@ -43,6 +47,8 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; +import java.util.Collections; + @SmallTest @RunWith(AndroidTestingRunner.class) @RunWithLooper @@ -269,6 +275,83 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { } } + /** Test for b/225902574. */ + @Test + public void vcnOnlyOnUnderlyingNetwork() { + setWifiEnabled(true); + + // Set up a carrier merged network... + WifiInfo underlyingCarrierMergedInfo = Mockito.mock(WifiInfo.class); + when(underlyingCarrierMergedInfo.isCarrierMerged()).thenReturn(true); + when(underlyingCarrierMergedInfo.isPrimary()).thenReturn(true); + int zeroLevel = 0; + when(underlyingCarrierMergedInfo.getRssi()).thenReturn(calculateRssiForLevel(zeroLevel)); + + 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(mMockCm.getNetworkCapabilities(underlyingNetwork)) + .thenReturn(underlyingNetworkCapabilities); + + NetworkCapabilities.Builder mainCapabilitiesBuilder = new NetworkCapabilities.Builder(); + mainCapabilitiesBuilder.addTransportType(TRANSPORT_CELLULAR); + mainCapabilitiesBuilder.setTransportInfo(null); + // And make the carrier merged network the underlying network, *not* the main network. + mainCapabilitiesBuilder.setUnderlyingNetworks(Collections.singletonList(underlyingNetwork)); + + Network primaryNetwork = Mockito.mock(Network.class); + int primaryNetworkId = 1; + when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId); + + // WHEN this primary network with underlying carrier merged information is sent + setConnectivityViaDefaultAndNormalCallbackInWifiTracker( + primaryNetwork, mainCapabilitiesBuilder.build()); + + // THEN we see the mobile data indicators for carrier merged + verifyLastMobileDataIndicatorsForVcn( + /* visible= */ true, + /* level= */ zeroLevel, + TelephonyIcons.ICON_CWF, + /* inet= */ false); + + // For each level... + for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) { + int rssi = calculateRssiForLevel(testLevel); + when(underlyingCarrierMergedInfo.getRssi()).thenReturn(rssi); + // WHEN the new level is sent to the callbacks + setConnectivityViaDefaultAndNormalCallbackInWifiTracker( + primaryNetwork, mainCapabilitiesBuilder.build()); + + // WHEN the network is validated + mainCapabilitiesBuilder.addCapability(NET_CAPABILITY_VALIDATED); + setConnectivityViaCallbackInNetworkController( + primaryNetwork, mainCapabilitiesBuilder.build()); + + // THEN we see the mobile data indicators with inet=true (no exclamation mark) + verifyLastMobileDataIndicatorsForVcn( + /* visible= */ true, + testLevel, + TelephonyIcons.ICON_CWF, + /* inet= */ true); + + // WHEN the network is not validated + mainCapabilitiesBuilder.removeCapability(NET_CAPABILITY_VALIDATED); + setConnectivityViaCallbackInNetworkController( + primaryNetwork, mainCapabilitiesBuilder.build()); + + // THEN we see the mobile data indicators with inet=false (exclamation mark) + verifyLastMobileDataIndicatorsForVcn( + /* visible= */ true, + testLevel, + TelephonyIcons.ICON_CWF, + /* inet= */ false); + } + } + @Test public void testDisableWiFiWithVcnWithUnderlyingWifi() { String testSsid = "Test VCN SSID"; @@ -290,11 +373,7 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { } protected void setWifiLevel(int level) { - float amountPerLevel = (MAX_RSSI - MIN_RSSI) / (WifiIcons.WIFI_LEVEL_COUNT - 1); - int rssi = (int) (MIN_RSSI + level * amountPerLevel); - // Put RSSI in the middle of the range. - rssi += amountPerLevel / 2; - when(mWifiInfo.getRssi()).thenReturn(rssi); + when(mWifiInfo.getRssi()).thenReturn(calculateRssiForLevel(level)); setConnectivityViaCallbackInWifiTracker( NetworkCapabilities.TRANSPORT_WIFI, false, true, mWifiInfo); } @@ -312,19 +391,23 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { } protected void setWifiLevelForVcn(int level) { - float amountPerLevel = (MAX_RSSI - MIN_RSSI) / (WifiIcons.WIFI_LEVEL_COUNT - 1); - int rssi = (int) (MIN_RSSI + level * amountPerLevel); - // Put RSSI in the middle of the range. - rssi += amountPerLevel / 2; when(mVcnTransportInfo.getWifiInfo()).thenReturn(mWifiInfo); when(mVcnTransportInfo.makeCopy(anyLong())).thenReturn(mVcnTransportInfo); - when(mWifiInfo.getRssi()).thenReturn(rssi); + when(mWifiInfo.getRssi()).thenReturn(calculateRssiForLevel(level)); when(mWifiInfo.isCarrierMerged()).thenReturn(true); when(mWifiInfo.getSubscriptionId()).thenReturn(1); setConnectivityViaCallbackInWifiTrackerForVcn( NetworkCapabilities.TRANSPORT_CELLULAR, false, true, mVcnTransportInfo); } + private int calculateRssiForLevel(int level) { + float amountPerLevel = (MAX_RSSI - MIN_RSSI) / (WifiIcons.WIFI_LEVEL_COUNT - 1); + int rssi = (int) (MIN_RSSI + level * amountPerLevel); + // Put RSSI in the middle of the range. + rssi += amountPerLevel / 2; + return rssi; + } + protected void setWifiStateForVcn(boolean connected, String ssid) { when(mVcnTransportInfo.getWifiInfo()).thenReturn(mWifiInfo); when(mVcnTransportInfo.makeCopy(anyLong())).thenReturn(mVcnTransportInfo);