diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeterTest.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeterTest.java index 532be675213..ec3dedb4558 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeterTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeterTest.java @@ -25,6 +25,7 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.Uri; +import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -32,6 +33,7 @@ import com.google.android.exoplayer2.testutil.FakeClock; import com.google.android.exoplayer2.testutil.FakeDataSource; import com.google.android.exoplayer2.util.NetworkTypeObserver; +import com.google.android.exoplayer2.util.Util; import java.util.Random; import org.junit.Before; import org.junit.Test; @@ -40,9 +42,11 @@ import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowLooper; import org.robolectric.shadows.ShadowNetworkInfo; +import org.robolectric.shadows.ShadowTelephonyManager; /** Unit test for {@link DefaultBandwidthMeter}. */ @RunWith(AndroidJUnit4.class) +@Config(sdk = Config.ALL_SDKS) // Test all SDKs because network detection logic changed over time. public final class DefaultBandwidthMeterTest { private static final int SIMULATED_TRANSFER_COUNT = 100; @@ -56,8 +60,6 @@ public final class DefaultBandwidthMeterTest { private NetworkInfo networkInfo2g; private NetworkInfo networkInfo3g; private NetworkInfo networkInfo4g; - // TODO: Add tests covering 5G-NSA networks. Not testable right now because we need to set the - // TelephonyDisplayInfo on API 31, which isn't available for Robolectric yet. private NetworkInfo networkInfo5gSa; private NetworkInfo networkInfoEthernet; @@ -183,9 +185,15 @@ public void defaultInitialBitrateEstimate_forEthernet_isGreaterThanEstimateFor3G assertThat(initialEstimateEthernet).isGreaterThan(initialEstimate3g); } - @Config(sdk = 28) // TODO(b/190021699): Fix 4G tests to work on newer API levels @Test public void defaultInitialBitrateEstimate_for4G_isGreaterThanEstimateFor2G() { + if (Util.SDK_INT == 29 || Util.SDK_INT == 30) { + // Robolectric doesn't support listening to service state changes, which we need on APIs 29 + // and 30 to run this test successfully. + // TODO(b/190021699): Update once Robolectric released support for this. + return; + } + setActiveNetworkInfo(networkInfo4g); DefaultBandwidthMeter bandwidthMeter4g = new DefaultBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build(); @@ -199,9 +207,15 @@ public void defaultInitialBitrateEstimate_for4G_isGreaterThanEstimateFor2G() { assertThat(initialEstimate4g).isGreaterThan(initialEstimate2g); } - @Config(sdk = 28) // TODO(b/190021699): Fix 4G tests to work on newer API levels @Test public void defaultInitialBitrateEstimate_for4G_isGreaterThanEstimateFor3G() { + if (Util.SDK_INT == 29 || Util.SDK_INT == 30) { + // Robolectric doesn't support listening to service state changes, which we need on APIs 29 + // and 30 to run this test successfully. + // TODO(b/190021699): Update once Robolectric released support for this. + return; + } + setActiveNetworkInfo(networkInfo4g); DefaultBandwidthMeter bandwidthMeter4g = new DefaultBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build(); @@ -231,18 +245,42 @@ public void defaultInitialBitrateEstimate_for3G_isGreaterThanEstimateFor2G() { } @Test - public void defaultInitialBitrateEstimate_for5gSa_isGreaterThanEstimateFor4g() { + @Config(minSdk = 29) // 5G detection support was added in API 29. + public void defaultInitialBitrateEstimate_for5gNsa_isGreaterThanEstimateFor4g() { + if (Util.SDK_INT == 29 || Util.SDK_INT == 30) { + // Robolectric doesn't support listening to service state changes, which we need on APIs 29 + // and 30 to run this test successfully. + // TODO(b/190021699): Update once Robolectric released support for this. + return; + } + setActiveNetworkInfo(networkInfo4g); DefaultBandwidthMeter bandwidthMeter4g = new DefaultBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build(); long initialEstimate4g = bandwidthMeter4g.getBitrateEstimate(); + setActiveNetworkInfo(networkInfo4g, TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA); + DefaultBandwidthMeter bandwidthMeter5gNsa = + new DefaultBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build(); + long initialEstimate5gNsa = bandwidthMeter5gNsa.getBitrateEstimate(); + + assertThat(initialEstimate5gNsa).isGreaterThan(initialEstimate4g); + } + + @Test + @Config(minSdk = 29) // 5G detection support was added in API 29. + public void defaultInitialBitrateEstimate_for5gSa_isGreaterThanEstimateFor3g() { + setActiveNetworkInfo(networkInfo3g); + DefaultBandwidthMeter bandwidthMeter3g = + new DefaultBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build(); + long initialEstimate3g = bandwidthMeter3g.getBitrateEstimate(); + setActiveNetworkInfo(networkInfo5gSa); DefaultBandwidthMeter bandwidthMeter5gSa = new DefaultBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build(); long initialEstimate5gSa = bandwidthMeter5gSa.getBitrateEstimate(); - assertThat(initialEstimate5gSa).isGreaterThan(initialEstimate4g); + assertThat(initialEstimate5gSa).isGreaterThan(initialEstimate3g); } @Test @@ -324,10 +362,16 @@ public void defaultInitialBitrateEstimate_forOffline_isReasonable() { assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow); } - @Config(sdk = 28) // TODO(b/190021699): Fix 4G tests to work on newer API levels @Test public void defaultInitialBitrateEstimate_for4g_forFastCountry_isGreaterThanEstimateForSlowCountry() { + if (Util.SDK_INT == 29 || Util.SDK_INT == 30) { + // Robolectric doesn't support listening to service state changes, which we need on APIs 29 + // and 30 to run this test successfully. + // TODO(b/190021699): Update once Robolectric released support for this. + return; + } + setActiveNetworkInfo(networkInfo4g); setNetworkCountryIso(FAST_COUNTRY_ISO); DefaultBandwidthMeter bandwidthMeterFast = @@ -343,6 +387,32 @@ public void defaultInitialBitrateEstimate_forOffline_isReasonable() { } @Test + @Config(minSdk = 29) // 5G detection support was added in API 29. + public void + defaultInitialBitrateEstimate_for5gNsa_forFastCountry_isGreaterThanEstimateForSlowCountry() { + if (Util.SDK_INT == 29 || Util.SDK_INT == 30) { + // Robolectric doesn't support listening to service state changes, which we need on APIs 29 + // and 30 to run this test successfully. + // TODO(b/190021699): Update once Robolectric released support for this. + return; + } + + setActiveNetworkInfo(networkInfo4g, TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA); + setNetworkCountryIso(FAST_COUNTRY_ISO); + DefaultBandwidthMeter bandwidthMeterFast = + new DefaultBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build(); + long initialEstimateFast = bandwidthMeterFast.getBitrateEstimate(); + + setNetworkCountryIso(SLOW_COUNTRY_ISO); + DefaultBandwidthMeter bandwidthMeterSlow = + new DefaultBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build(); + long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate(); + + assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow); + } + + @Test + @Config(minSdk = 29) // 5G detection support was added in API 29. public void defaultInitialBitrateEstimate_for5gSa_forFastCountry_isGreaterThanEstimateForSlowCountry() { setActiveNetworkInfo(networkInfo5gSa); @@ -484,9 +554,15 @@ public void initialBitrateEstimateOverwrite_for3G_whileConnectedTo3G_setsInitial assertThat(initialEstimate).isNotEqualTo(123456789); } - @Config(sdk = 28) // TODO(b/190021699): Fix 4G tests to work on newer API levels @Test public void initialBitrateEstimateOverwrite_for4G_whileConnectedTo4G_setsInitialEstimate() { + if (Util.SDK_INT == 29 || Util.SDK_INT == 30) { + // Robolectric doesn't support listening to service state changes, which we need on APIs 29 + // and 30 to run this test successfully. + // TODO(b/190021699): Update once Robolectric released support for this. + return; + } + setActiveNetworkInfo(networkInfo4g); DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()) @@ -497,7 +573,6 @@ public void initialBitrateEstimateOverwrite_for4G_whileConnectedTo4G_setsInitial assertThat(initialEstimate).isEqualTo(123456789); } - @Config(sdk = 28) // TODO(b/190021699): Fix 4G tests to work on newer API levels @Test public void initialBitrateEstimateOverwrite_for4G_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() { @@ -512,6 +587,41 @@ public void initialBitrateEstimateOverwrite_for4G_whileConnectedTo4G_setsInitial } @Test + @Config(minSdk = 29) // 5G detection support was added in API 29. + public void initialBitrateEstimateOverwrite_for5gNsa_whileConnectedTo5gNsa_setsInitialEstimate() { + if (Util.SDK_INT == 29 || Util.SDK_INT == 30) { + // Robolectric doesn't support listening to service state changes, which we need on APIs 29 + // and 30 to run this test successfully. + // TODO(b/190021699): Update once Robolectric released support for this. + return; + } + + setActiveNetworkInfo(networkInfo4g, TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA); + DefaultBandwidthMeter bandwidthMeter = + new DefaultBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()) + .setInitialBitrateEstimate(C.NETWORK_TYPE_5G_NSA, 123456789) + .build(); + long initialEstimate = bandwidthMeter.getBitrateEstimate(); + + assertThat(initialEstimate).isEqualTo(123456789); + } + + @Test + @Config(minSdk = 29) // 5G detection support was added in API 29. + public void + initialBitrateEstimateOverwrite_for5gNsa_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() { + setActiveNetworkInfo(networkInfo4g); + DefaultBandwidthMeter bandwidthMeter = + new DefaultBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()) + .setInitialBitrateEstimate(C.NETWORK_TYPE_5G_NSA, 123456789) + .build(); + long initialEstimate = bandwidthMeter.getBitrateEstimate(); + + assertThat(initialEstimate).isNotEqualTo(123456789); + } + + @Test + @Config(minSdk = 29) // 5G detection support was added in API 29. public void initialBitrateEstimateOverwrite_for5gSa_whileConnectedTo5gSa_setsInitialEstimate() { setActiveNetworkInfo(networkInfo5gSa); DefaultBandwidthMeter bandwidthMeter = @@ -524,6 +634,7 @@ public void initialBitrateEstimateOverwrite_for5gSa_whileConnectedTo5gSa_setsIni } @Test + @Config(minSdk = 29) // 5G detection support was added in API 29. public void initialBitrateEstimateOverwrite_for5gSa_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() { setActiveNetworkInfo(networkInfoWifi); @@ -636,11 +747,27 @@ public void defaultInitialBitrateEstimate_withoutContext_isReasonable() { assertThat(initialEstimateWithoutBuilder).isLessThan(50_000_000L); } - @SuppressWarnings("StickyBroadcast") private void setActiveNetworkInfo(NetworkInfo networkInfo) { + setActiveNetworkInfo(networkInfo, TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE); + } + + @SuppressWarnings("StickyBroadcast") + private void setActiveNetworkInfo(NetworkInfo networkInfo, int networkTypeOverride) { + // Set network info in ConnectivityManager and TelephonyDisplayInfo in TelephonyManager. Shadows.shadowOf(connectivityManager).setActiveNetworkInfo(networkInfo); + if (Util.SDK_INT >= 31) { + Object displayInfo = + ShadowTelephonyManager.createTelephonyDisplayInfo( + networkInfo.getType(), networkTypeOverride); + Shadows.shadowOf(telephonyManager).setTelephonyDisplayInfo(displayInfo); + } + // Create a sticky broadcast for the connectivity action because Roboletric isn't replying with + // the current network state if a receiver for this intent is registered. ApplicationProvider.getApplicationContext() .sendStickyBroadcast(new Intent(ConnectivityManager.CONNECTIVITY_ACTION)); + // Trigger initialization of static network type observer. + NetworkTypeObserver.getInstance(ApplicationProvider.getApplicationContext()); + // Wait until all pending messages are handled and the network initialization is done. ShadowLooper.idleMainLooper(); }