Add 5G-NSA detection.
PiperOrigin-RevId: 364607555
This commit is contained in:
parent
c202d406fb
commit
b35c81124d
@ -930,8 +930,8 @@ public final class C {
|
|||||||
/**
|
/**
|
||||||
* Network connection type. One of {@link #NETWORK_TYPE_UNKNOWN}, {@link #NETWORK_TYPE_OFFLINE},
|
* Network connection type. One of {@link #NETWORK_TYPE_UNKNOWN}, {@link #NETWORK_TYPE_OFFLINE},
|
||||||
* {@link #NETWORK_TYPE_WIFI}, {@link #NETWORK_TYPE_2G}, {@link #NETWORK_TYPE_3G}, {@link
|
* {@link #NETWORK_TYPE_WIFI}, {@link #NETWORK_TYPE_2G}, {@link #NETWORK_TYPE_3G}, {@link
|
||||||
* #NETWORK_TYPE_4G}, {@link #NETWORK_TYPE_5G}, {@link #NETWORK_TYPE_CELLULAR_UNKNOWN}, {@link
|
* #NETWORK_TYPE_4G}, {@link #NETWORK_TYPE_5G_SA}, {@link #NETWORK_TYPE_5G_NSA}, {@link
|
||||||
* #NETWORK_TYPE_ETHERNET} or {@link #NETWORK_TYPE_OTHER}.
|
* #NETWORK_TYPE_CELLULAR_UNKNOWN}, {@link #NETWORK_TYPE_ETHERNET} or {@link #NETWORK_TYPE_OTHER}.
|
||||||
*/
|
*/
|
||||||
@Documented
|
@Documented
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@ -942,7 +942,8 @@ public final class C {
|
|||||||
NETWORK_TYPE_2G,
|
NETWORK_TYPE_2G,
|
||||||
NETWORK_TYPE_3G,
|
NETWORK_TYPE_3G,
|
||||||
NETWORK_TYPE_4G,
|
NETWORK_TYPE_4G,
|
||||||
NETWORK_TYPE_5G,
|
NETWORK_TYPE_5G_SA,
|
||||||
|
NETWORK_TYPE_5G_NSA,
|
||||||
NETWORK_TYPE_CELLULAR_UNKNOWN,
|
NETWORK_TYPE_CELLULAR_UNKNOWN,
|
||||||
NETWORK_TYPE_ETHERNET,
|
NETWORK_TYPE_ETHERNET,
|
||||||
NETWORK_TYPE_OTHER
|
NETWORK_TYPE_OTHER
|
||||||
@ -960,8 +961,10 @@ public final class C {
|
|||||||
public static final int NETWORK_TYPE_3G = 4;
|
public static final int NETWORK_TYPE_3G = 4;
|
||||||
/** Network type for a 4G cellular connection. */
|
/** Network type for a 4G cellular connection. */
|
||||||
public static final int NETWORK_TYPE_4G = 5;
|
public static final int NETWORK_TYPE_4G = 5;
|
||||||
/** Network type for a 5G cellular connection. */
|
/** Network type for a 5G stand-alone (SA) cellular connection. */
|
||||||
public static final int NETWORK_TYPE_5G = 9;
|
public static final int NETWORK_TYPE_5G_SA = 9;
|
||||||
|
/** Network type for a 5G non-stand-alone (NSA) cellular connection. */
|
||||||
|
public static final int NETWORK_TYPE_5G_NSA = 10;
|
||||||
/**
|
/**
|
||||||
* Network type for cellular connections which cannot be mapped to one of {@link
|
* Network type for cellular connections which cannot be mapped to one of {@link
|
||||||
* #NETWORK_TYPE_2G}, {@link #NETWORK_TYPE_3G}, or {@link #NETWORK_TYPE_4G}.
|
* #NETWORK_TYPE_2G}, {@link #NETWORK_TYPE_3G}, or {@link #NETWORK_TYPE_4G}.
|
||||||
|
@ -207,7 +207,7 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
|
|||||||
|
|
||||||
private static Map<Integer, Long> getInitialBitrateEstimatesForCountry(String countryCode) {
|
private static Map<Integer, Long> getInitialBitrateEstimatesForCountry(String countryCode) {
|
||||||
List<Integer> groupIndices = getCountryGroupIndices(countryCode);
|
List<Integer> groupIndices = getCountryGroupIndices(countryCode);
|
||||||
Map<Integer, Long> result = new HashMap<>(/* initialCapacity= */ 6);
|
Map<Integer, Long> result = new HashMap<>(/* initialCapacity= */ 8);
|
||||||
result.put(C.NETWORK_TYPE_UNKNOWN, DEFAULT_INITIAL_BITRATE_ESTIMATE);
|
result.put(C.NETWORK_TYPE_UNKNOWN, DEFAULT_INITIAL_BITRATE_ESTIMATE);
|
||||||
result.put(
|
result.put(
|
||||||
C.NETWORK_TYPE_WIFI,
|
C.NETWORK_TYPE_WIFI,
|
||||||
@ -222,7 +222,12 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
|
|||||||
C.NETWORK_TYPE_4G,
|
C.NETWORK_TYPE_4G,
|
||||||
DEFAULT_INITIAL_BITRATE_ESTIMATES_4G.get(groupIndices.get(COUNTRY_GROUP_INDEX_4G)));
|
DEFAULT_INITIAL_BITRATE_ESTIMATES_4G.get(groupIndices.get(COUNTRY_GROUP_INDEX_4G)));
|
||||||
result.put(
|
result.put(
|
||||||
C.NETWORK_TYPE_5G,
|
C.NETWORK_TYPE_5G_NSA,
|
||||||
|
DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_NSA.get(
|
||||||
|
groupIndices.get(COUNTRY_GROUP_INDEX_5G_NSA)));
|
||||||
|
result.put(
|
||||||
|
C.NETWORK_TYPE_5G_SA,
|
||||||
|
// TODO: Retrieve actual 5G-SA estimates.
|
||||||
DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_NSA.get(
|
DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_NSA.get(
|
||||||
groupIndices.get(COUNTRY_GROUP_INDEX_5G_NSA)));
|
groupIndices.get(COUNTRY_GROUP_INDEX_5G_NSA)));
|
||||||
// Assume default Wifi speed for Ethernet to prevent using the slower fallback.
|
// Assume default Wifi speed for Ethernet to prevent using the slower fallback.
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.util;
|
package com.google.android.exoplayer2.util;
|
||||||
|
|
||||||
|
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@ -23,6 +25,8 @@ import android.net.ConnectivityManager;
|
|||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.telephony.PhoneStateListener;
|
||||||
|
import android.telephony.ServiceState;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import androidx.annotation.GuardedBy;
|
import androidx.annotation.GuardedBy;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@ -196,7 +200,7 @@ public final class NetworkTypeObserver {
|
|||||||
case TelephonyManager.NETWORK_TYPE_LTE:
|
case TelephonyManager.NETWORK_TYPE_LTE:
|
||||||
return C.NETWORK_TYPE_4G;
|
return C.NETWORK_TYPE_4G;
|
||||||
case TelephonyManager.NETWORK_TYPE_NR:
|
case TelephonyManager.NETWORK_TYPE_NR:
|
||||||
return Util.SDK_INT >= 29 ? C.NETWORK_TYPE_5G : C.NETWORK_TYPE_UNKNOWN;
|
return Util.SDK_INT >= 29 ? C.NETWORK_TYPE_5G_SA : C.NETWORK_TYPE_UNKNOWN;
|
||||||
case TelephonyManager.NETWORK_TYPE_IWLAN:
|
case TelephonyManager.NETWORK_TYPE_IWLAN:
|
||||||
return C.NETWORK_TYPE_WIFI;
|
return C.NETWORK_TYPE_WIFI;
|
||||||
case TelephonyManager.NETWORK_TYPE_GSM:
|
case TelephonyManager.NETWORK_TYPE_GSM:
|
||||||
@ -211,7 +215,36 @@ public final class NetworkTypeObserver {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
@C.NetworkType int networkType = getNetworkTypeFromConnectivityManager(context);
|
@C.NetworkType int networkType = getNetworkTypeFromConnectivityManager(context);
|
||||||
|
if (networkType == C.NETWORK_TYPE_4G && Util.SDK_INT >= 29 && Util.SDK_INT < 31) {
|
||||||
|
// Delay update of the network type to check whether this is actually 5G-NSA.
|
||||||
|
try {
|
||||||
|
// We can't access TelephonyManager.getServiceState() directly as it requires special
|
||||||
|
// permissions. Attaching a listener is permission-free.
|
||||||
|
TelephonyManager telephonyManager =
|
||||||
|
checkNotNull((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE));
|
||||||
|
ServiceStateListener listener = new ServiceStateListener();
|
||||||
|
telephonyManager.listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE);
|
||||||
|
// We are only interested in the initial response with the current state, so unregister
|
||||||
|
// the listener immediately.
|
||||||
|
telephonyManager.listen(listener, PhoneStateListener.LISTEN_NONE);
|
||||||
|
return;
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
// Ignore problems with listener registration and keep reporting as 4G.
|
||||||
|
}
|
||||||
|
}
|
||||||
updateNetworkType(networkType);
|
updateNetworkType(networkType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ServiceStateListener extends PhoneStateListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceStateChanged(@Nullable ServiceState serviceState) {
|
||||||
|
String serviceStateString = serviceState == null ? "" : serviceState.toString();
|
||||||
|
boolean is5gNsa =
|
||||||
|
serviceStateString.contains("nrState=CONNECTED")
|
||||||
|
|| serviceStateString.contains("nrState=NOT_RESTRICTED");
|
||||||
|
updateNetworkType(is5gNsa ? C.NETWORK_TYPE_5G_NSA : C.NETWORK_TYPE_4G);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.Shadows;
|
import org.robolectric.Shadows;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
import org.robolectric.shadows.ShadowLooper;
|
import org.robolectric.shadows.ShadowLooper;
|
||||||
import org.robolectric.shadows.ShadowNetworkInfo;
|
import org.robolectric.shadows.ShadowNetworkInfo;
|
||||||
|
|
||||||
@ -45,7 +46,7 @@ import org.robolectric.shadows.ShadowNetworkInfo;
|
|||||||
public final class DefaultBandwidthMeterTest {
|
public final class DefaultBandwidthMeterTest {
|
||||||
|
|
||||||
private static final int SIMULATED_TRANSFER_COUNT = 100;
|
private static final int SIMULATED_TRANSFER_COUNT = 100;
|
||||||
private static final String FAST_COUNTRY_ISO = "EE";
|
private static final String FAST_COUNTRY_ISO = "TW";
|
||||||
private static final String SLOW_COUNTRY_ISO = "PG";
|
private static final String SLOW_COUNTRY_ISO = "PG";
|
||||||
|
|
||||||
private TelephonyManager telephonyManager;
|
private TelephonyManager telephonyManager;
|
||||||
@ -55,6 +56,9 @@ public final class DefaultBandwidthMeterTest {
|
|||||||
private NetworkInfo networkInfo2g;
|
private NetworkInfo networkInfo2g;
|
||||||
private NetworkInfo networkInfo3g;
|
private NetworkInfo networkInfo3g;
|
||||||
private NetworkInfo networkInfo4g;
|
private NetworkInfo networkInfo4g;
|
||||||
|
// TODO: Add tests covering 5G-NSA networks. Not testable right now because Robolectric's
|
||||||
|
// ShadowTelephonyManager doesn't handle requests to return the ServiceState.
|
||||||
|
private NetworkInfo networkInfo5gSa;
|
||||||
private NetworkInfo networkInfoEthernet;
|
private NetworkInfo networkInfoEthernet;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@ -103,6 +107,13 @@ public final class DefaultBandwidthMeterTest {
|
|||||||
TelephonyManager.NETWORK_TYPE_LTE,
|
TelephonyManager.NETWORK_TYPE_LTE,
|
||||||
/* isAvailable= */ true,
|
/* isAvailable= */ true,
|
||||||
CONNECTED);
|
CONNECTED);
|
||||||
|
networkInfo5gSa =
|
||||||
|
ShadowNetworkInfo.newInstance(
|
||||||
|
DetailedState.CONNECTED,
|
||||||
|
ConnectivityManager.TYPE_MOBILE,
|
||||||
|
TelephonyManager.NETWORK_TYPE_NR,
|
||||||
|
/* isAvailable= */ true,
|
||||||
|
CONNECTED);
|
||||||
networkInfoEthernet =
|
networkInfoEthernet =
|
||||||
ShadowNetworkInfo.newInstance(
|
ShadowNetworkInfo.newInstance(
|
||||||
DetailedState.CONNECTED,
|
DetailedState.CONNECTED,
|
||||||
@ -217,6 +228,22 @@ public final class DefaultBandwidthMeterTest {
|
|||||||
assertThat(initialEstimate3g).isGreaterThan(initialEstimate2g);
|
assertThat(initialEstimate3g).isGreaterThan(initialEstimate2g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Config(sdk = Config.NEWEST_SDK) // TODO: Remove once targetSDK >= 29
|
||||||
|
@Test
|
||||||
|
public void defaultInitialBitrateEstimate_for5gSa_isGreaterThanEstimateFor4g() {
|
||||||
|
setActiveNetworkInfo(networkInfo4g);
|
||||||
|
DefaultBandwidthMeter bandwidthMeter4g =
|
||||||
|
new DefaultBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||||
|
long initialEstimate4g = bandwidthMeter4g.getBitrateEstimate();
|
||||||
|
|
||||||
|
setActiveNetworkInfo(networkInfo5gSa);
|
||||||
|
DefaultBandwidthMeter bandwidthMeter5gSa =
|
||||||
|
new DefaultBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
|
||||||
|
long initialEstimate5gSa = bandwidthMeter5gSa.getBitrateEstimate();
|
||||||
|
|
||||||
|
assertThat(initialEstimate5gSa).isGreaterThan(initialEstimate4g);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void defaultInitialBitrateEstimate_forOffline_isReasonable() {
|
public void defaultInitialBitrateEstimate_forOffline_isReasonable() {
|
||||||
setActiveNetworkInfo(networkInfoOffline);
|
setActiveNetworkInfo(networkInfoOffline);
|
||||||
@ -313,6 +340,24 @@ public final class DefaultBandwidthMeterTest {
|
|||||||
assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow);
|
assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Config(sdk = Config.NEWEST_SDK) // TODO: Remove once targetSDK >= 29
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
defaultInitialBitrateEstimate_for5gSa_forFastCountry_isGreaterThanEstimateForSlowCountry() {
|
||||||
|
setActiveNetworkInfo(networkInfo5gSa);
|
||||||
|
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
|
@Test
|
||||||
public void initialBitrateEstimateOverwrite_whileConnectedToNetwork_setsInitialEstimate() {
|
public void initialBitrateEstimateOverwrite_whileConnectedToNetwork_setsInitialEstimate() {
|
||||||
setActiveNetworkInfo(networkInfoWifi);
|
setActiveNetworkInfo(networkInfoWifi);
|
||||||
@ -463,6 +508,33 @@ public final class DefaultBandwidthMeterTest {
|
|||||||
assertThat(initialEstimate).isNotEqualTo(123456789);
|
assertThat(initialEstimate).isNotEqualTo(123456789);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Config(sdk = Config.NEWEST_SDK) // TODO: Remove once targetSDK >= 29
|
||||||
|
@Test
|
||||||
|
public void initialBitrateEstimateOverwrite_for5gSa_whileConnectedTo5gSa_setsInitialEstimate() {
|
||||||
|
setActiveNetworkInfo(networkInfo5gSa);
|
||||||
|
DefaultBandwidthMeter bandwidthMeter =
|
||||||
|
new DefaultBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||||
|
.setInitialBitrateEstimate(C.NETWORK_TYPE_5G_SA, 123456789)
|
||||||
|
.build();
|
||||||
|
long initialEstimate = bandwidthMeter.getBitrateEstimate();
|
||||||
|
|
||||||
|
assertThat(initialEstimate).isEqualTo(123456789);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Config(sdk = Config.NEWEST_SDK) // TODO: Remove once targetSDK >= 29
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
initialBitrateEstimateOverwrite_for5gSa_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() {
|
||||||
|
setActiveNetworkInfo(networkInfoWifi);
|
||||||
|
DefaultBandwidthMeter bandwidthMeter =
|
||||||
|
new DefaultBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
|
||||||
|
.setInitialBitrateEstimate(C.NETWORK_TYPE_5G_SA, 123456789)
|
||||||
|
.build();
|
||||||
|
long initialEstimate = bandwidthMeter.getBitrateEstimate();
|
||||||
|
|
||||||
|
assertThat(initialEstimate).isNotEqualTo(123456789);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void initialBitrateEstimateOverwrite_forOffline_whileOffline_setsInitialEstimate() {
|
public void initialBitrateEstimateOverwrite_forOffline_whileOffline_setsInitialEstimate() {
|
||||||
setActiveNetworkInfo(networkInfoOffline);
|
setActiveNetworkInfo(networkInfoOffline);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user