diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java index 3cbf2685af268..ff70eda68a5d9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -1,6 +1,7 @@ package com.android.settingslib; import android.annotation.ColorInt; +import android.annotation.Nullable; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -23,6 +24,9 @@ import android.graphics.drawable.Drawable; import android.location.LocationManager; import android.media.AudioManager; import android.net.ConnectivityManager; +import android.net.NetworkCapabilities; +import android.net.vcn.VcnTransportInfo; +import android.net.wifi.WifiInfo; import android.os.BatteryManager; import android.os.SystemProperties; import android.os.UserHandle; @@ -563,4 +567,21 @@ public class Utils { drawable.draw(canvas); return roundedBitmap; } + + /** + * Returns the WifiInfo for the underlying WiFi network of the VCN network, returns null if the + * input NetworkCapabilities is not for a VCN network with underlying WiFi network. + * + * @param networkCapabilities NetworkCapabilities of the network. + */ + @Nullable + public static WifiInfo tryGetWifiInfoForVcn(NetworkCapabilities networkCapabilities) { + if (networkCapabilities.getTransportInfo() == null + || !(networkCapabilities.getTransportInfo() instanceof VcnTransportInfo)) { + return null; + } + VcnTransportInfo vcnTransportInfo = + (VcnTransportInfo) networkCapabilities.getTransportInfo(); + return vcnTransportInfo.getWifiInfo(); + } } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java index 15bacbfe8fb26..5580afe70faf0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java @@ -36,6 +36,7 @@ import android.provider.Settings; import android.util.FeatureFlagUtils; import com.android.settingslib.R; +import com.android.settingslib.Utils; import java.util.List; @@ -60,17 +61,25 @@ public class WifiStatusTracker { private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder() .clearCapabilities() .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build(); + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).build(); private final NetworkCallback mNetworkCallback = new NetworkCallback() { // Note: onCapabilitiesChanged is guaranteed to be called "immediately" after onAvailable // and onLinkPropertiesChanged. @Override public void onCapabilitiesChanged( Network network, NetworkCapabilities networkCapabilities) { - WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo(); - updateWifiInfo(wifiInfo); - updateStatusLabel(); - mCallback.run(); + WifiInfo wifiInfo = null; + if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + wifiInfo = Utils.tryGetWifiInfoForVcn(networkCapabilities); + } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { + wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo(); + } + if (wifiInfo != null) { + updateWifiInfo(wifiInfo); + updateStatusLabel(); + mCallback.run(); + } } @Override @@ -238,8 +247,14 @@ public class WifiStatusTracker { NetworkCapabilities networkCapabilities; isDefaultNetwork = false; if (mDefaultNetworkCapabilities != null) { - isDefaultNetwork = mDefaultNetworkCapabilities.hasTransport( + boolean isWifi = mDefaultNetworkCapabilities.hasTransport( NetworkCapabilities.TRANSPORT_WIFI); + boolean isVcnOverWifi = mDefaultNetworkCapabilities.hasTransport( + NetworkCapabilities.TRANSPORT_CELLULAR) + && (Utils.tryGetWifiInfoForVcn(mDefaultNetworkCapabilities) != null); + if (isWifi || isVcnOverWifi) { + isDefaultNetwork = true; + } } if (isDefaultNetwork) { // Wifi is connected and the default network. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index f1ccde771c545..f9450ae4d5248 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -59,6 +59,7 @@ import androidx.annotation.NonNull; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.settingslib.Utils; import com.android.settingslib.mobile.MobileMappings.Config; import com.android.settingslib.mobile.MobileStatusTracker.SubscriptionDefaults; import com.android.settingslib.mobile.TelephonyIcons; @@ -919,9 +920,17 @@ public class NetworkControllerImpl extends BroadcastReceiver for (NetworkCapabilities nc : mConnectivityManager.getDefaultNetworkCapabilitiesForUser(mCurrentUserId)) { for (int transportType : nc.getTransportTypes()) { - mConnectedTransports.set(transportType); - if (nc.hasCapability(NET_CAPABILITY_VALIDATED)) { - mValidatedTransports.set(transportType); + if (transportType == NetworkCapabilities.TRANSPORT_CELLULAR + && Utils.tryGetWifiInfoForVcn(nc) != null) { + mConnectedTransports.set(NetworkCapabilities.TRANSPORT_WIFI); + if (nc.hasCapability(NET_CAPABILITY_VALIDATED)) { + mValidatedTransports.set(NetworkCapabilities.TRANSPORT_WIFI); + } + } else { + mConnectedTransports.set(transportType); + if (nc.hasCapability(NET_CAPABILITY_VALIDATED)) { + mValidatedTransports.set(transportType); + } } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index c83835b5453e2..deabcbe520b61 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -41,6 +41,7 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.NetworkScoreManager; +import android.net.vcn.VcnTransportInfo; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Handler; @@ -182,6 +183,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { if (rssi < -55) return 3; return 4; }).when(mMockWm).calculateSignalLevel(anyInt()); + when(mMockWm.getMaxSignalLevel()).thenReturn(4); mSignalStrength = mock(SignalStrength.class); mServiceState = mock(ServiceState.class); @@ -308,6 +310,14 @@ public class NetworkControllerBaseTest extends SysuiTestCase { NetworkCapabilities.TRANSPORT_CELLULAR, true, true); } + public void setConnectivityViaBroadcastForVcn( + int networkType, boolean validated, boolean isConnected, VcnTransportInfo info) { + mNetCapabilities.setTransportInfo(info); + setConnectivityCommon(networkType, validated, isConnected); + Intent i = new Intent(ConnectivityManager.INET_CONDITION_ACTION); + mNetworkController.onReceive(mContext, i); + } + public void setConnectivityViaBroadcast( int networkType, boolean validated, boolean isConnected) { setConnectivityCommon(networkType, validated, isConnected); @@ -341,6 +351,20 @@ public class NetworkControllerBaseTest extends SysuiTestCase { } } + public void setConnectivityViaCallbackInWifiTrackerForVcn( + int networkType, boolean validated, boolean isConnected, VcnTransportInfo info) { + mNetCapabilities.setTransportInfo(info); + setConnectivityCommon(networkType, validated, isConnected); + if (networkType == NetworkCapabilities.TRANSPORT_CELLULAR) { + if (isConnected) { + mNetworkCallback.onCapabilitiesChanged( + mock(Network.class), new NetworkCapabilities(mNetCapabilities)); + } else { + mNetworkCallback.onLost(mock(Network.class)); + } + } + } + public void setConnectivityViaDefaultCallbackInWifiTracker( int networkType, boolean validated, boolean isConnected, WifiInfo wifiInfo) { if (networkType == NetworkCapabilities.TRANSPORT_WIFI) { @@ -509,6 +533,26 @@ public class NetworkControllerBaseTest extends SysuiTestCase { assertEquals("Visibility in status bar", visible, iconState.visible); } + protected void verifyLastMobileDataIndicatorsForVcn(boolean visible, int level, int typeIcon, + boolean inet) { + ArgumentCaptor iconArg = ArgumentCaptor.forClass(IconState.class); + ArgumentCaptor typeIconArg = ArgumentCaptor.forClass(Integer.class); + + verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators( + iconArg.capture(), + any(), + typeIconArg.capture(), + anyInt(), anyBoolean(), anyBoolean(), + any(CharSequence.class), any(CharSequence.class), any(), + anyBoolean(), anyInt(), anyBoolean()); + IconState iconState = iconArg.getValue(); + int state = SignalDrawable.getState( + level, CellSignalStrength.getNumSignalStrengthLevels(), !inet); + assertEquals("Signal icon in status bar", state, iconState.icon); + assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue()); + assertEquals("Visibility in status bar", visible, iconState.visible); + } + protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon, boolean qsVisible, int qsIcon, int qsTypeIcon, boolean dataIn, boolean dataOut) { verifyLastMobileDataIndicators( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java index 44c5edb21eebe..2b82f66cb4c20 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java @@ -12,12 +12,14 @@ import android.content.Intent; import android.net.ConnectivityManager; import android.net.NetworkCapabilities; import android.net.NetworkInfo; +import android.net.vcn.VcnTransportInfo; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; +import com.android.settingslib.mobile.TelephonyIcons; import com.android.systemui.statusbar.policy.NetworkController.IconState; import org.junit.Before; @@ -34,6 +36,7 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { private static final int MIN_RSSI = -100; private static final int MAX_RSSI = -55; private WifiInfo mWifiInfo = mock(WifiInfo.class); + private VcnTransportInfo mVcnTransportInfo = mock(VcnTransportInfo.class); @Before public void setUp() throws Exception { @@ -214,6 +217,32 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { assertEquals(testSsid, mNetworkController.mWifiSignalController.mCurrentState.ssid); } + @Test + public void testVcnWithUnderlyingWifi() { + String testSsid = "Test VCN SSID"; + setWifiEnabled(true); + verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK); + + setWifiStateForVcn(true, testSsid); + setWifiLevelForVcn(0); + + // Connected, but still not validated - does not show + //verifyLastWifiIcon(false, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]); + verifyLastMobileDataIndicatorsForVcn(false, 0, TelephonyIcons.ICON_CWF, false); + + for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) { + setWifiLevelForVcn(testLevel); + + setConnectivityViaBroadcastForVcn( + NetworkCapabilities.TRANSPORT_CELLULAR, true, true, mVcnTransportInfo); + verifyLastMobileDataIndicatorsForVcn(true, testLevel, TelephonyIcons.ICON_CWF, true); + + setConnectivityViaBroadcastForVcn( + NetworkCapabilities.TRANSPORT_CELLULAR, false, true, mVcnTransportInfo); + verifyLastMobileDataIndicatorsForVcn(false, testLevel, TelephonyIcons.ICON_CWF, false); + } + } + protected void setWifiActivity(int activity) { // TODO: Not this, because this variable probably isn't sticking around. mNetworkController.mWifiSignalController.setActivity(activity); @@ -241,6 +270,28 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest { NetworkCapabilities.TRANSPORT_WIFI, false, connected, mWifiInfo); } + 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(mWifiInfo.getRssi()).thenReturn(rssi); + when(mWifiInfo.isCarrierMerged()).thenReturn(true); + when(mWifiInfo.getSubscriptionId()).thenReturn(1); + setConnectivityViaCallbackInWifiTrackerForVcn( + NetworkCapabilities.TRANSPORT_CELLULAR, false, true, mVcnTransportInfo); + } + + protected void setWifiStateForVcn(boolean connected, String ssid) { + when(mVcnTransportInfo.getWifiInfo()).thenReturn(mWifiInfo); + when(mWifiInfo.getSSID()).thenReturn(ssid); + when(mWifiInfo.isCarrierMerged()).thenReturn(true); + when(mWifiInfo.getSubscriptionId()).thenReturn(1); + setConnectivityViaCallbackInWifiTrackerForVcn( + NetworkCapabilities.TRANSPORT_CELLULAR, false, connected, mVcnTransportInfo); + } + protected void verifyLastQsDataDirection(boolean in, boolean out) { ArgumentCaptor inArg = ArgumentCaptor.forClass(Boolean.class); ArgumentCaptor outArg = ArgumentCaptor.forClass(Boolean.class);