diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 65c9b6fb3a..cd8caa0c8a 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -2,6 +2,8 @@
### 2.9.1 ###
+* Improve initial bandwidth meter estimates using the current country and
+ network type.
* SubRip: Add support for alignment tags, and remove tags from the displayed
captions ([#4306](https://github.com/google/ExoPlayer/issues/4306)).
* MP3: Support seeking based on MLLT metadata
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java
index 6e0fba27ae..e9f70ec92a 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeter.java
@@ -15,20 +15,57 @@
*/
package com.google.android.exoplayer2.upstream;
+import android.content.Context;
import android.os.Handler;
import android.support.annotation.Nullable;
+import android.util.SparseArray;
+import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.EventDispatcher;
import com.google.android.exoplayer2.util.SlidingPercentile;
+import com.google.android.exoplayer2.util.Util;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
/**
- * Estimates bandwidth by listening to data transfers. The bandwidth estimate is calculated using a
- * {@link SlidingPercentile} and is updated each time a transfer ends.
+ * Estimates bandwidth by listening to data transfers.
+ *
+ *
The bandwidth estimate is calculated using a {@link SlidingPercentile} and is updated each
+ * time a transfer ends. The initial estimate is based on the current operator's network country
+ * code or the locale of the user, as well as the network connection type. This can be configured in
+ * the {@link Builder}.
*/
public final class DefaultBandwidthMeter implements BandwidthMeter, TransferListener {
- /** Default initial bitrate estimate in bits per second. */
+ /**
+ * Country groups used to determine the default initial bitrate estimate. The group assignment for
+ * each country is an array of group indices for [Wifi, 2G, 3G, 4G].
+ */
+ public static final Map DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS =
+ createInitialBitrateCountryGroupAssignment();
+
+ /** Default initial Wifi bitrate estimate in bits per second. */
+ public static final long[] DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI =
+ new long[] {5_700_000, 3_400_000, 1_900_000, 1_000_000, 400_000};
+
+ /** Default initial 2G bitrate estimates in bits per second. */
+ public static final long[] DEFAULT_INITIAL_BITRATE_ESTIMATES_2G =
+ new long[] {169_000, 129_000, 114_000, 102_000, 87_000};
+
+ /** Default initial 3G bitrate estimates in bits per second. */
+ public static final long[] DEFAULT_INITIAL_BITRATE_ESTIMATES_3G =
+ new long[] {2_100_000, 1_300_000, 950_000, 700_000, 400_000};
+
+ /** Default initial 4G bitrate estimates in bits per second. */
+ public static final long[] DEFAULT_INITIAL_BITRATE_ESTIMATES_4G =
+ new long[] {6_900_000, 4_300_000, 2_700_000, 1_600_000, 450_000};
+
+ /**
+ * Default initial bitrate estimate used when the device is offline or the network type cannot be
+ * determined, in bits per second.
+ */
public static final long DEFAULT_INITIAL_BITRATE_ESTIMATE = 1_000_000;
/** Default maximum weight for the sliding window. */
@@ -37,15 +74,28 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
/** Builder for a bandwidth meter. */
public static final class Builder {
- private @Nullable Handler eventHandler;
- private @Nullable EventListener eventListener;
- private long initialBitrateEstimate;
+ @Nullable private final Context context;
+
+ @Nullable private Handler eventHandler;
+ @Nullable private EventListener eventListener;
+ private SparseArray initialBitrateEstimates;
private int slidingWindowMaxWeight;
private Clock clock;
- /** Creates a builder with default parameters and without listener. */
+ /** @deprecated Use {@link #Builder(Context)} instead. */
+ @Deprecated
public Builder() {
- initialBitrateEstimate = DEFAULT_INITIAL_BITRATE_ESTIMATE;
+ this(/* context= */ null);
+ }
+
+ /**
+ * Creates a builder with default parameters and without listener.
+ *
+ * @param context A context.
+ */
+ public Builder(@Nullable Context context) {
+ this.context = context == null ? null : context.getApplicationContext();
+ initialBitrateEstimates = getInitialBitrateEstimatesForCountry(Util.getCountryCode(context));
slidingWindowMaxWeight = DEFAULT_SLIDING_WINDOW_MAX_WEIGHT;
clock = Clock.DEFAULT;
}
@@ -84,7 +134,38 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
* @return This builder.
*/
public Builder setInitialBitrateEstimate(long initialBitrateEstimate) {
- this.initialBitrateEstimate = initialBitrateEstimate;
+ for (int i = 0; i < initialBitrateEstimates.size(); i++) {
+ initialBitrateEstimates.setValueAt(i, initialBitrateEstimate);
+ }
+ return this;
+ }
+
+ /**
+ * Sets the initial bitrate estimate in bits per second for a network type that should be
+ * assumed when a bandwidth estimate is unavailable and the current network connection is of the
+ * specified type.
+ *
+ * @param networkType The {@link C.NetworkType} this initial estimate is for.
+ * @param initialBitrateEstimate The initial bitrate estimate in bits per second.
+ * @return This builder.
+ */
+ public Builder setInitialBitrateEstimate(
+ @C.NetworkType int networkType, long initialBitrateEstimate) {
+ initialBitrateEstimates.put(networkType, initialBitrateEstimate);
+ return this;
+ }
+
+ /**
+ * Sets the initial bitrate estimates to the default values of the specified country. The
+ * initial estimates are used when a bandwidth estimate is unavailable.
+ *
+ * @param countryCode The ISO 3166-1 alpha-2 country code of the country whose default bitrate
+ * estimates should be used.
+ * @return This builder.
+ */
+ public Builder setInitialBitrateEstimate(String countryCode) {
+ initialBitrateEstimates =
+ getInitialBitrateEstimatesForCountry(Util.toUpperInvariant(countryCode));
return this;
}
@@ -106,6 +187,10 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
* @return A bandwidth meter with the configured properties.
*/
public DefaultBandwidthMeter build() {
+ Long initialBitrateEstimate = initialBitrateEstimates.get(Util.getNetworkType(context));
+ if (initialBitrateEstimate == null) {
+ initialBitrateEstimate = initialBitrateEstimates.get(C.NETWORK_TYPE_UNKNOWN);
+ }
DefaultBandwidthMeter bandwidthMeter =
new DefaultBandwidthMeter(initialBitrateEstimate, slidingWindowMaxWeight, clock);
if (eventHandler != null && eventListener != null) {
@@ -113,6 +198,26 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
}
return bandwidthMeter;
}
+
+ private static SparseArray getInitialBitrateEstimatesForCountry(String countryCode) {
+ int[] groupIndices = getCountryGroupIndices(countryCode);
+ SparseArray result = new SparseArray<>(/* initialCapacity= */ 6);
+ result.append(C.NETWORK_TYPE_UNKNOWN, DEFAULT_INITIAL_BITRATE_ESTIMATE);
+ result.append(C.NETWORK_TYPE_WIFI, DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI[groupIndices[0]]);
+ result.append(C.NETWORK_TYPE_2G, DEFAULT_INITIAL_BITRATE_ESTIMATES_2G[groupIndices[1]]);
+ result.append(C.NETWORK_TYPE_3G, DEFAULT_INITIAL_BITRATE_ESTIMATES_3G[groupIndices[2]]);
+ result.append(C.NETWORK_TYPE_4G, DEFAULT_INITIAL_BITRATE_ESTIMATES_4G[groupIndices[3]]);
+ // Assume default Wifi bitrate for Ethernet to prevent using the slower fallback bitrate.
+ result.append(
+ C.NETWORK_TYPE_ETHERNET, DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI[groupIndices[0]]);
+ return result;
+ }
+
+ private static int[] getCountryGroupIndices(String countryCode) {
+ int[] groupIndices = DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS.get(countryCode);
+ // Assume median group if not found.
+ return groupIndices == null ? new int[] {2, 2, 2, 2} : groupIndices;
+ }
}
private static final int ELAPSED_MILLIS_FOR_ESTIMATE = 2000;
@@ -153,10 +258,7 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
}
}
- private DefaultBandwidthMeter(
- long initialBitrateEstimate,
- int maxWeight,
- Clock clock) {
+ private DefaultBandwidthMeter(long initialBitrateEstimate, int maxWeight, Clock clock) {
this.eventDispatcher = new EventDispatcher<>();
this.slidingPercentile = new SlidingPercentile(maxWeight);
this.clock = clock;
@@ -169,7 +271,8 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
}
@Override
- public @Nullable TransferListener getTransferListener() {
+ @Nullable
+ public TransferListener getTransferListener() {
return this;
}
@@ -237,4 +340,249 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
private void notifyBandwidthSample(int elapsedMs, long bytes, long bitrate) {
eventDispatcher.dispatch(listener -> listener.onBandwidthSample(elapsedMs, bytes, bitrate));
}
+
+ private static Map createInitialBitrateCountryGroupAssignment() {
+ HashMap countryGroupAssignment = new HashMap<>();
+ countryGroupAssignment.put("AD", new int[] {1, 0, 0, 0});
+ countryGroupAssignment.put("AE", new int[] {1, 3, 4, 4});
+ countryGroupAssignment.put("AF", new int[] {4, 4, 3, 2});
+ countryGroupAssignment.put("AG", new int[] {3, 2, 1, 2});
+ countryGroupAssignment.put("AI", new int[] {1, 0, 0, 2});
+ countryGroupAssignment.put("AL", new int[] {1, 1, 1, 1});
+ countryGroupAssignment.put("AM", new int[] {2, 2, 4, 3});
+ countryGroupAssignment.put("AO", new int[] {2, 4, 2, 0});
+ countryGroupAssignment.put("AR", new int[] {2, 3, 2, 3});
+ countryGroupAssignment.put("AS", new int[] {3, 4, 4, 1});
+ countryGroupAssignment.put("AT", new int[] {0, 1, 0, 0});
+ countryGroupAssignment.put("AU", new int[] {0, 3, 0, 0});
+ countryGroupAssignment.put("AW", new int[] {1, 1, 0, 4});
+ countryGroupAssignment.put("AX", new int[] {0, 1, 0, 0});
+ countryGroupAssignment.put("AZ", new int[] {3, 3, 2, 2});
+ countryGroupAssignment.put("BA", new int[] {1, 1, 1, 2});
+ countryGroupAssignment.put("BB", new int[] {0, 1, 0, 0});
+ countryGroupAssignment.put("BD", new int[] {2, 1, 3, 2});
+ countryGroupAssignment.put("BE", new int[] {0, 0, 0, 0});
+ countryGroupAssignment.put("BF", new int[] {4, 4, 4, 1});
+ countryGroupAssignment.put("BG", new int[] {0, 0, 0, 1});
+ countryGroupAssignment.put("BH", new int[] {2, 1, 3, 4});
+ countryGroupAssignment.put("BI", new int[] {4, 3, 4, 4});
+ countryGroupAssignment.put("BJ", new int[] {4, 3, 4, 3});
+ countryGroupAssignment.put("BL", new int[] {1, 0, 1, 2});
+ countryGroupAssignment.put("BM", new int[] {1, 0, 0, 0});
+ countryGroupAssignment.put("BN", new int[] {4, 3, 3, 3});
+ countryGroupAssignment.put("BO", new int[] {2, 2, 1, 2});
+ countryGroupAssignment.put("BQ", new int[] {1, 1, 2, 4});
+ countryGroupAssignment.put("BR", new int[] {2, 3, 2, 2});
+ countryGroupAssignment.put("BS", new int[] {1, 1, 0, 2});
+ countryGroupAssignment.put("BT", new int[] {3, 0, 2, 1});
+ countryGroupAssignment.put("BW", new int[] {4, 4, 2, 3});
+ countryGroupAssignment.put("BY", new int[] {1, 1, 1, 1});
+ countryGroupAssignment.put("BZ", new int[] {2, 3, 3, 1});
+ countryGroupAssignment.put("CA", new int[] {0, 2, 2, 3});
+ countryGroupAssignment.put("CD", new int[] {4, 4, 2, 1});
+ countryGroupAssignment.put("CF", new int[] {4, 4, 3, 3});
+ countryGroupAssignment.put("CG", new int[] {4, 4, 4, 4});
+ countryGroupAssignment.put("CH", new int[] {0, 0, 0, 0});
+ countryGroupAssignment.put("CI", new int[] {4, 4, 4, 4});
+ countryGroupAssignment.put("CK", new int[] {2, 4, 2, 0});
+ countryGroupAssignment.put("CL", new int[] {2, 2, 2, 3});
+ countryGroupAssignment.put("CM", new int[] {3, 4, 3, 1});
+ countryGroupAssignment.put("CN", new int[] {2, 0, 1, 2});
+ countryGroupAssignment.put("CO", new int[] {2, 3, 2, 1});
+ countryGroupAssignment.put("CR", new int[] {2, 2, 4, 4});
+ countryGroupAssignment.put("CU", new int[] {4, 4, 4, 1});
+ countryGroupAssignment.put("CV", new int[] {2, 2, 2, 4});
+ countryGroupAssignment.put("CW", new int[] {1, 1, 0, 0});
+ countryGroupAssignment.put("CX", new int[] {1, 2, 2, 2});
+ countryGroupAssignment.put("CY", new int[] {1, 1, 0, 0});
+ countryGroupAssignment.put("CZ", new int[] {0, 1, 0, 0});
+ countryGroupAssignment.put("DE", new int[] {0, 2, 2, 2});
+ countryGroupAssignment.put("DJ", new int[] {3, 4, 4, 0});
+ countryGroupAssignment.put("DK", new int[] {0, 0, 0, 0});
+ countryGroupAssignment.put("DM", new int[] {2, 0, 3, 4});
+ countryGroupAssignment.put("DO", new int[] {3, 3, 4, 4});
+ countryGroupAssignment.put("DZ", new int[] {3, 3, 4, 4});
+ countryGroupAssignment.put("EC", new int[] {2, 3, 3, 1});
+ countryGroupAssignment.put("EE", new int[] {0, 0, 0, 0});
+ countryGroupAssignment.put("EG", new int[] {3, 3, 1, 1});
+ countryGroupAssignment.put("EH", new int[] {2, 0, 2, 3});
+ countryGroupAssignment.put("ER", new int[] {4, 2, 2, 2});
+ countryGroupAssignment.put("ES", new int[] {0, 0, 1, 1});
+ countryGroupAssignment.put("ET", new int[] {4, 4, 4, 0});
+ countryGroupAssignment.put("FI", new int[] {0, 0, 1, 0});
+ countryGroupAssignment.put("FJ", new int[] {3, 2, 3, 3});
+ countryGroupAssignment.put("FK", new int[] {3, 4, 2, 1});
+ countryGroupAssignment.put("FM", new int[] {4, 2, 4, 0});
+ countryGroupAssignment.put("FO", new int[] {0, 0, 0, 1});
+ countryGroupAssignment.put("FR", new int[] {1, 0, 2, 1});
+ countryGroupAssignment.put("GA", new int[] {3, 3, 2, 1});
+ countryGroupAssignment.put("GB", new int[] {0, 1, 3, 2});
+ countryGroupAssignment.put("GD", new int[] {2, 0, 3, 0});
+ countryGroupAssignment.put("GE", new int[] {1, 1, 0, 3});
+ countryGroupAssignment.put("GF", new int[] {1, 2, 4, 4});
+ countryGroupAssignment.put("GG", new int[] {0, 1, 0, 0});
+ countryGroupAssignment.put("GH", new int[] {3, 2, 2, 2});
+ countryGroupAssignment.put("GI", new int[] {0, 0, 0, 1});
+ countryGroupAssignment.put("GL", new int[] {2, 4, 1, 4});
+ countryGroupAssignment.put("GM", new int[] {4, 3, 3, 0});
+ countryGroupAssignment.put("GN", new int[] {4, 4, 3, 4});
+ countryGroupAssignment.put("GP", new int[] {2, 2, 1, 3});
+ countryGroupAssignment.put("GQ", new int[] {4, 4, 3, 1});
+ countryGroupAssignment.put("GR", new int[] {1, 1, 0, 1});
+ countryGroupAssignment.put("GT", new int[] {3, 2, 3, 4});
+ countryGroupAssignment.put("GU", new int[] {1, 0, 4, 4});
+ countryGroupAssignment.put("GW", new int[] {4, 4, 4, 0});
+ countryGroupAssignment.put("GY", new int[] {3, 4, 1, 0});
+ countryGroupAssignment.put("HK", new int[] {0, 2, 3, 4});
+ countryGroupAssignment.put("HN", new int[] {3, 3, 2, 2});
+ countryGroupAssignment.put("HR", new int[] {1, 0, 0, 2});
+ countryGroupAssignment.put("HT", new int[] {3, 3, 3, 3});
+ countryGroupAssignment.put("HU", new int[] {0, 0, 1, 0});
+ countryGroupAssignment.put("ID", new int[] {2, 3, 3, 4});
+ countryGroupAssignment.put("IE", new int[] {0, 0, 1, 1});
+ countryGroupAssignment.put("IL", new int[] {0, 1, 1, 3});
+ countryGroupAssignment.put("IM", new int[] {0, 1, 0, 1});
+ countryGroupAssignment.put("IN", new int[] {2, 3, 3, 4});
+ countryGroupAssignment.put("IO", new int[] {4, 2, 2, 2});
+ countryGroupAssignment.put("IQ", new int[] {3, 3, 4, 3});
+ countryGroupAssignment.put("IR", new int[] {3, 2, 4, 4});
+ countryGroupAssignment.put("IS", new int[] {0, 0, 0, 0});
+ countryGroupAssignment.put("IT", new int[] {1, 0, 1, 3});
+ countryGroupAssignment.put("JE", new int[] {0, 0, 0, 1});
+ countryGroupAssignment.put("JM", new int[] {3, 3, 3, 2});
+ countryGroupAssignment.put("JO", new int[] {1, 1, 1, 2});
+ countryGroupAssignment.put("JP", new int[] {0, 1, 1, 2});
+ countryGroupAssignment.put("KE", new int[] {3, 3, 3, 3});
+ countryGroupAssignment.put("KG", new int[] {2, 2, 3, 3});
+ countryGroupAssignment.put("KH", new int[] {1, 0, 4, 4});
+ countryGroupAssignment.put("KI", new int[] {4, 4, 4, 4});
+ countryGroupAssignment.put("KM", new int[] {4, 4, 2, 2});
+ countryGroupAssignment.put("KN", new int[] {1, 0, 1, 3});
+ countryGroupAssignment.put("KP", new int[] {1, 2, 2, 2});
+ countryGroupAssignment.put("KR", new int[] {0, 4, 0, 2});
+ countryGroupAssignment.put("KW", new int[] {1, 2, 1, 2});
+ countryGroupAssignment.put("KY", new int[] {1, 1, 0, 2});
+ countryGroupAssignment.put("KZ", new int[] {1, 2, 2, 3});
+ countryGroupAssignment.put("LA", new int[] {3, 2, 2, 2});
+ countryGroupAssignment.put("LB", new int[] {3, 2, 0, 0});
+ countryGroupAssignment.put("LC", new int[] {2, 2, 1, 0});
+ countryGroupAssignment.put("LI", new int[] {0, 0, 1, 2});
+ countryGroupAssignment.put("LK", new int[] {1, 1, 2, 2});
+ countryGroupAssignment.put("LR", new int[] {3, 4, 3, 1});
+ countryGroupAssignment.put("LS", new int[] {3, 3, 2, 0});
+ countryGroupAssignment.put("LT", new int[] {0, 0, 0, 1});
+ countryGroupAssignment.put("LU", new int[] {0, 0, 1, 0});
+ countryGroupAssignment.put("LV", new int[] {0, 0, 0, 0});
+ countryGroupAssignment.put("LY", new int[] {4, 4, 4, 4});
+ countryGroupAssignment.put("MA", new int[] {2, 1, 2, 2});
+ countryGroupAssignment.put("MC", new int[] {1, 0, 1, 0});
+ countryGroupAssignment.put("MD", new int[] {1, 1, 0, 0});
+ countryGroupAssignment.put("ME", new int[] {1, 2, 2, 3});
+ countryGroupAssignment.put("MF", new int[] {1, 4, 3, 3});
+ countryGroupAssignment.put("MG", new int[] {3, 4, 1, 2});
+ countryGroupAssignment.put("MH", new int[] {4, 0, 2, 3});
+ countryGroupAssignment.put("MK", new int[] {1, 0, 0, 1});
+ countryGroupAssignment.put("ML", new int[] {4, 4, 4, 4});
+ countryGroupAssignment.put("MM", new int[] {2, 3, 1, 2});
+ countryGroupAssignment.put("MN", new int[] {2, 2, 2, 4});
+ countryGroupAssignment.put("MO", new int[] {0, 1, 4, 4});
+ countryGroupAssignment.put("MP", new int[] {0, 0, 4, 4});
+ countryGroupAssignment.put("MQ", new int[] {1, 1, 1, 3});
+ countryGroupAssignment.put("MR", new int[] {4, 2, 4, 2});
+ countryGroupAssignment.put("MS", new int[] {1, 2, 1, 2});
+ countryGroupAssignment.put("MT", new int[] {0, 0, 0, 0});
+ countryGroupAssignment.put("MU", new int[] {2, 2, 4, 4});
+ countryGroupAssignment.put("MV", new int[] {4, 2, 0, 1});
+ countryGroupAssignment.put("MW", new int[] {3, 2, 1, 1});
+ countryGroupAssignment.put("MX", new int[] {2, 4, 3, 1});
+ countryGroupAssignment.put("MY", new int[] {2, 3, 3, 3});
+ countryGroupAssignment.put("MZ", new int[] {3, 3, 2, 4});
+ countryGroupAssignment.put("NA", new int[] {4, 2, 1, 1});
+ countryGroupAssignment.put("NC", new int[] {2, 1, 3, 3});
+ countryGroupAssignment.put("NE", new int[] {4, 4, 4, 4});
+ countryGroupAssignment.put("NF", new int[] {0, 2, 2, 2});
+ countryGroupAssignment.put("NG", new int[] {3, 4, 2, 2});
+ countryGroupAssignment.put("NI", new int[] {3, 4, 3, 3});
+ countryGroupAssignment.put("NL", new int[] {0, 1, 3, 2});
+ countryGroupAssignment.put("NO", new int[] {0, 0, 1, 0});
+ countryGroupAssignment.put("NP", new int[] {2, 3, 2, 2});
+ countryGroupAssignment.put("NR", new int[] {4, 3, 4, 1});
+ countryGroupAssignment.put("NU", new int[] {4, 2, 2, 2});
+ countryGroupAssignment.put("NZ", new int[] {0, 0, 0, 1});
+ countryGroupAssignment.put("OM", new int[] {2, 2, 1, 3});
+ countryGroupAssignment.put("PA", new int[] {1, 3, 2, 3});
+ countryGroupAssignment.put("PE", new int[] {2, 2, 4, 4});
+ countryGroupAssignment.put("PF", new int[] {2, 2, 0, 1});
+ countryGroupAssignment.put("PG", new int[] {4, 4, 4, 4});
+ countryGroupAssignment.put("PH", new int[] {3, 0, 4, 4});
+ countryGroupAssignment.put("PK", new int[] {3, 3, 3, 3});
+ countryGroupAssignment.put("PL", new int[] {1, 0, 1, 3});
+ countryGroupAssignment.put("PM", new int[] {0, 2, 2, 3});
+ countryGroupAssignment.put("PR", new int[] {2, 3, 4, 3});
+ countryGroupAssignment.put("PS", new int[] {2, 3, 0, 4});
+ countryGroupAssignment.put("PT", new int[] {1, 1, 1, 1});
+ countryGroupAssignment.put("PW", new int[] {3, 2, 3, 0});
+ countryGroupAssignment.put("PY", new int[] {2, 1, 3, 3});
+ countryGroupAssignment.put("QA", new int[] {2, 3, 1, 2});
+ countryGroupAssignment.put("RE", new int[] {1, 1, 2, 2});
+ countryGroupAssignment.put("RO", new int[] {0, 1, 1, 3});
+ countryGroupAssignment.put("RS", new int[] {1, 1, 0, 0});
+ countryGroupAssignment.put("RU", new int[] {0, 1, 1, 1});
+ countryGroupAssignment.put("RW", new int[] {3, 4, 3, 1});
+ countryGroupAssignment.put("SA", new int[] {3, 2, 2, 3});
+ countryGroupAssignment.put("SB", new int[] {4, 4, 3, 0});
+ countryGroupAssignment.put("SC", new int[] {4, 2, 0, 1});
+ countryGroupAssignment.put("SD", new int[] {3, 4, 4, 4});
+ countryGroupAssignment.put("SE", new int[] {0, 0, 0, 0});
+ countryGroupAssignment.put("SG", new int[] {1, 2, 3, 3});
+ countryGroupAssignment.put("SH", new int[] {4, 2, 2, 2});
+ countryGroupAssignment.put("SI", new int[] {0, 1, 0, 0});
+ countryGroupAssignment.put("SJ", new int[] {3, 2, 0, 2});
+ countryGroupAssignment.put("SK", new int[] {0, 1, 0, 1});
+ countryGroupAssignment.put("SL", new int[] {4, 3, 2, 4});
+ countryGroupAssignment.put("SM", new int[] {1, 0, 1, 1});
+ countryGroupAssignment.put("SN", new int[] {4, 4, 4, 2});
+ countryGroupAssignment.put("SO", new int[] {4, 4, 4, 3});
+ countryGroupAssignment.put("SR", new int[] {3, 2, 2, 3});
+ countryGroupAssignment.put("SS", new int[] {4, 3, 4, 2});
+ countryGroupAssignment.put("ST", new int[] {3, 2, 2, 2});
+ countryGroupAssignment.put("SV", new int[] {2, 3, 2, 3});
+ countryGroupAssignment.put("SX", new int[] {2, 4, 2, 0});
+ countryGroupAssignment.put("SY", new int[] {4, 4, 2, 0});
+ countryGroupAssignment.put("SZ", new int[] {3, 4, 1, 1});
+ countryGroupAssignment.put("TC", new int[] {2, 1, 2, 1});
+ countryGroupAssignment.put("TD", new int[] {4, 4, 4, 3});
+ countryGroupAssignment.put("TG", new int[] {3, 2, 2, 0});
+ countryGroupAssignment.put("TH", new int[] {1, 3, 4, 4});
+ countryGroupAssignment.put("TJ", new int[] {4, 4, 4, 4});
+ countryGroupAssignment.put("TL", new int[] {4, 2, 4, 4});
+ countryGroupAssignment.put("TM", new int[] {4, 1, 3, 3});
+ countryGroupAssignment.put("TN", new int[] {2, 2, 1, 2});
+ countryGroupAssignment.put("TO", new int[] {2, 3, 3, 1});
+ countryGroupAssignment.put("TR", new int[] {1, 2, 0, 2});
+ countryGroupAssignment.put("TT", new int[] {2, 1, 1, 0});
+ countryGroupAssignment.put("TV", new int[] {4, 2, 2, 4});
+ countryGroupAssignment.put("TW", new int[] {0, 0, 0, 1});
+ countryGroupAssignment.put("TZ", new int[] {3, 3, 3, 2});
+ countryGroupAssignment.put("UA", new int[] {0, 2, 1, 3});
+ countryGroupAssignment.put("UG", new int[] {4, 3, 2, 2});
+ countryGroupAssignment.put("US", new int[] {0, 1, 3, 3});
+ countryGroupAssignment.put("UY", new int[] {2, 1, 2, 2});
+ countryGroupAssignment.put("UZ", new int[] {4, 3, 2, 4});
+ countryGroupAssignment.put("VA", new int[] {1, 2, 2, 2});
+ countryGroupAssignment.put("VC", new int[] {2, 0, 3, 2});
+ countryGroupAssignment.put("VE", new int[] {3, 4, 4, 3});
+ countryGroupAssignment.put("VG", new int[] {3, 1, 3, 4});
+ countryGroupAssignment.put("VI", new int[] {1, 0, 2, 4});
+ countryGroupAssignment.put("VN", new int[] {0, 2, 4, 4});
+ countryGroupAssignment.put("VU", new int[] {4, 1, 3, 2});
+ countryGroupAssignment.put("WS", new int[] {3, 2, 3, 0});
+ countryGroupAssignment.put("XK", new int[] {1, 2, 1, 0});
+ countryGroupAssignment.put("YE", new int[] {4, 4, 4, 2});
+ countryGroupAssignment.put("YT", new int[] {3, 1, 1, 2});
+ countryGroupAssignment.put("ZA", new int[] {2, 3, 1, 2});
+ countryGroupAssignment.put("ZM", new int[] {3, 3, 3, 1});
+ countryGroupAssignment.put("ZW", new int[] {3, 3, 2, 1});
+ return Collections.unmodifiableMap(countryGroupAssignment);
+ }
}
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
new file mode 100644
index 0000000000..ebdb45909b
--- /dev/null
+++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/DefaultBandwidthMeterTest.java
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.exoplayer2.upstream;
+
+import static android.Manifest.permission.ACCESS_NETWORK_STATE;
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
+import android.telephony.TelephonyManager;
+import com.google.android.exoplayer2.C;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
+import org.robolectric.shadows.ShadowNetworkInfo;
+
+/** Unit test for {@link DefaultBandwidthMeter}. */
+@RunWith(RobolectricTestRunner.class)
+public final class DefaultBandwidthMeterTest {
+
+ private static final String FAST_COUNTRY_ISO = "EE";
+ private static final String SLOW_COUNTRY_ISO = "PG";
+
+ private TelephonyManager telephonyManager;
+ private ConnectivityManager connectivityManager;
+ private NetworkInfo networkInfoOffline;
+ private NetworkInfo networkInfoWifi;
+ private NetworkInfo networkInfo2g;
+ private NetworkInfo networkInfo3g;
+ private NetworkInfo networkInfo4g;
+ private NetworkInfo networkInfoEthernet;
+
+ @Before
+ public void setUp() {
+ connectivityManager =
+ (ConnectivityManager)
+ RuntimeEnvironment.application.getSystemService(Context.CONNECTIVITY_SERVICE);
+ telephonyManager =
+ (TelephonyManager)
+ RuntimeEnvironment.application.getSystemService(Context.TELEPHONY_SERVICE);
+ Shadows.shadowOf(telephonyManager).setNetworkCountryIso(FAST_COUNTRY_ISO);
+ networkInfoOffline =
+ ShadowNetworkInfo.newInstance(
+ DetailedState.DISCONNECTED,
+ ConnectivityManager.TYPE_WIFI,
+ /* subType= */ 0,
+ /* isAvailable= */ false,
+ /* isConnected= */ false);
+ networkInfoWifi =
+ ShadowNetworkInfo.newInstance(
+ DetailedState.CONNECTED,
+ ConnectivityManager.TYPE_WIFI,
+ /* subType= */ 0,
+ /* isAvailable= */ true,
+ /* isConnected= */ true);
+ networkInfo2g =
+ ShadowNetworkInfo.newInstance(
+ DetailedState.CONNECTED,
+ ConnectivityManager.TYPE_MOBILE,
+ TelephonyManager.NETWORK_TYPE_GPRS,
+ /* isAvailable= */ true,
+ /* isConnected= */ true);
+ networkInfo3g =
+ ShadowNetworkInfo.newInstance(
+ DetailedState.CONNECTED,
+ ConnectivityManager.TYPE_MOBILE,
+ TelephonyManager.NETWORK_TYPE_HSDPA,
+ /* isAvailable= */ true,
+ /* isConnected= */ true);
+ networkInfo4g =
+ ShadowNetworkInfo.newInstance(
+ DetailedState.CONNECTED,
+ ConnectivityManager.TYPE_MOBILE,
+ TelephonyManager.NETWORK_TYPE_LTE,
+ /* isAvailable= */ true,
+ /* isConnected= */ true);
+ networkInfoEthernet =
+ ShadowNetworkInfo.newInstance(
+ DetailedState.CONNECTED,
+ ConnectivityManager.TYPE_ETHERNET,
+ /* subType= */ 0,
+ /* isAvailable= */ true,
+ /* isConnected= */ true);
+ }
+
+ @Test
+ public void defaultInitialBitrateEstimate_forWifi_isGreaterThanEstimateFor2G() {
+ setActiveNetworkInfo(networkInfoWifi);
+ DefaultBandwidthMeter bandwidthMeterWifi =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimateWifi = bandwidthMeterWifi.getBitrateEstimate();
+
+ setActiveNetworkInfo(networkInfo2g);
+ DefaultBandwidthMeter bandwidthMeter2g =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimate2g = bandwidthMeter2g.getBitrateEstimate();
+
+ assertThat(initialEstimateWifi).isGreaterThan(initialEstimate2g);
+ }
+
+ @Test
+ public void defaultInitialBitrateEstimate_forWifi_isGreaterThanEstimateFor3G() {
+ setActiveNetworkInfo(networkInfoWifi);
+ DefaultBandwidthMeter bandwidthMeterWifi =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimateWifi = bandwidthMeterWifi.getBitrateEstimate();
+
+ setActiveNetworkInfo(networkInfo3g);
+ DefaultBandwidthMeter bandwidthMeter3g =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimate3g = bandwidthMeter3g.getBitrateEstimate();
+
+ assertThat(initialEstimateWifi).isGreaterThan(initialEstimate3g);
+ }
+
+ @Test
+ public void defaultInitialBitrateEstimate_forEthernet_isGreaterThanEstimateFor2G() {
+ setActiveNetworkInfo(networkInfoEthernet);
+ DefaultBandwidthMeter bandwidthMeterEthernet =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimateEthernet = bandwidthMeterEthernet.getBitrateEstimate();
+
+ setActiveNetworkInfo(networkInfo2g);
+ DefaultBandwidthMeter bandwidthMeter2g =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimate2g = bandwidthMeter2g.getBitrateEstimate();
+
+ assertThat(initialEstimateEthernet).isGreaterThan(initialEstimate2g);
+ }
+
+ @Test
+ public void defaultInitialBitrateEstimate_forEthernet_isGreaterThanEstimateFor3G() {
+ setActiveNetworkInfo(networkInfoEthernet);
+ DefaultBandwidthMeter bandwidthMeterEthernet =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimateEthernet = bandwidthMeterEthernet.getBitrateEstimate();
+
+ setActiveNetworkInfo(networkInfo3g);
+ DefaultBandwidthMeter bandwidthMeter3g =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimate3g = bandwidthMeter3g.getBitrateEstimate();
+
+ assertThat(initialEstimateEthernet).isGreaterThan(initialEstimate3g);
+ }
+
+ @Test
+ public void defaultInitialBitrateEstimate_for4G_isGreaterThanEstimateFor2G() {
+ setActiveNetworkInfo(networkInfo4g);
+ DefaultBandwidthMeter bandwidthMeter4g =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimate4g = bandwidthMeter4g.getBitrateEstimate();
+
+ setActiveNetworkInfo(networkInfo2g);
+ DefaultBandwidthMeter bandwidthMeter2g =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimate2g = bandwidthMeter2g.getBitrateEstimate();
+
+ assertThat(initialEstimate4g).isGreaterThan(initialEstimate2g);
+ }
+
+ @Test
+ public void defaultInitialBitrateEstimate_for4G_isGreaterThanEstimateFor3G() {
+ setActiveNetworkInfo(networkInfo4g);
+ DefaultBandwidthMeter bandwidthMeter4g =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimate4g = bandwidthMeter4g.getBitrateEstimate();
+
+ setActiveNetworkInfo(networkInfo3g);
+ DefaultBandwidthMeter bandwidthMeter3g =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimate3g = bandwidthMeter3g.getBitrateEstimate();
+
+ assertThat(initialEstimate4g).isGreaterThan(initialEstimate3g);
+ }
+
+ @Test
+ public void defaultInitialBitrateEstimate_for3G_isGreaterThanEstimateFor2G() {
+ setActiveNetworkInfo(networkInfo3g);
+ DefaultBandwidthMeter bandwidthMeter3g =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimate3g = bandwidthMeter3g.getBitrateEstimate();
+
+ setActiveNetworkInfo(networkInfo2g);
+ DefaultBandwidthMeter bandwidthMeter2g =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimate2g = bandwidthMeter2g.getBitrateEstimate();
+
+ assertThat(initialEstimate3g).isGreaterThan(initialEstimate2g);
+ }
+
+ @Test
+ public void defaultInitialBitrateEstimate_forOffline_isReasonable() {
+ setActiveNetworkInfo(networkInfoOffline);
+ DefaultBandwidthMeter bandwidthMeter =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimate = bandwidthMeter.getBitrateEstimate();
+
+ assertThat(initialEstimate).isGreaterThan(100_000L);
+ assertThat(initialEstimate).isLessThan(50_000_000L);
+ }
+
+ @Test
+ public void
+ defaultInitialBitrateEstimate_forWifi_forFastCountry_isGreaterThanEstimateForSlowCountry() {
+ setActiveNetworkInfo(networkInfoWifi);
+ setNetworkCountryIso(FAST_COUNTRY_ISO);
+ DefaultBandwidthMeter bandwidthMeterFast =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimateFast = bandwidthMeterFast.getBitrateEstimate();
+
+ setNetworkCountryIso(SLOW_COUNTRY_ISO);
+ DefaultBandwidthMeter bandwidthMeterSlow =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
+
+ assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow);
+ }
+
+ @Test
+ public void
+ defaultInitialBitrateEstimate_forEthernet_forFastCountry_isGreaterThanEstimateForSlowCountry() {
+ setActiveNetworkInfo(networkInfoEthernet);
+ setNetworkCountryIso(FAST_COUNTRY_ISO);
+ DefaultBandwidthMeter bandwidthMeterFast =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimateFast = bandwidthMeterFast.getBitrateEstimate();
+
+ setNetworkCountryIso(SLOW_COUNTRY_ISO);
+ DefaultBandwidthMeter bandwidthMeterSlow =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
+
+ assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow);
+ }
+
+ @Test
+ public void
+ defaultInitialBitrateEstimate_for2G_forFastCountry_isGreaterThanEstimateForSlowCountry() {
+ setActiveNetworkInfo(networkInfo2g);
+ setNetworkCountryIso(FAST_COUNTRY_ISO);
+ DefaultBandwidthMeter bandwidthMeterFast =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimateFast = bandwidthMeterFast.getBitrateEstimate();
+
+ setNetworkCountryIso(SLOW_COUNTRY_ISO);
+ DefaultBandwidthMeter bandwidthMeterSlow =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
+
+ assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow);
+ }
+
+ @Test
+ public void
+ defaultInitialBitrateEstimate_for3G_forFastCountry_isGreaterThanEstimateForSlowCountry() {
+ setActiveNetworkInfo(networkInfo3g);
+ setNetworkCountryIso(FAST_COUNTRY_ISO);
+ DefaultBandwidthMeter bandwidthMeterFast =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimateFast = bandwidthMeterFast.getBitrateEstimate();
+
+ setNetworkCountryIso(SLOW_COUNTRY_ISO);
+ DefaultBandwidthMeter bandwidthMeterSlow =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
+
+ assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow);
+ }
+
+ @Test
+ public void
+ defaultInitialBitrateEstimate_for4g_forFastCountry_isGreaterThanEstimateForSlowCountry() {
+ setActiveNetworkInfo(networkInfo4g);
+ setNetworkCountryIso(FAST_COUNTRY_ISO);
+ DefaultBandwidthMeter bandwidthMeterFast =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimateFast = bandwidthMeterFast.getBitrateEstimate();
+
+ setNetworkCountryIso(SLOW_COUNTRY_ISO);
+ DefaultBandwidthMeter bandwidthMeterSlow =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
+
+ assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow);
+ }
+
+ @Test
+ public void initialBitrateEstimateOverwrite_whileConnectedToNetwork_setsInitialEstimate() {
+ setActiveNetworkInfo(networkInfoWifi);
+ DefaultBandwidthMeter bandwidthMeter =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application)
+ .setInitialBitrateEstimate(123456789)
+ .build();
+ long initialEstimate = bandwidthMeter.getBitrateEstimate();
+
+ assertThat(initialEstimate).isEqualTo(123456789);
+ }
+
+ @Test
+ public void initialBitrateEstimateOverwrite_whileOffline_setsInitialEstimate() {
+ setActiveNetworkInfo(networkInfoOffline);
+ DefaultBandwidthMeter bandwidthMeter =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application)
+ .setInitialBitrateEstimate(123456789)
+ .build();
+ long initialEstimate = bandwidthMeter.getBitrateEstimate();
+
+ assertThat(initialEstimate).isEqualTo(123456789);
+ }
+
+ @Test
+ public void initialBitrateEstimateOverwrite_forWifi_whileConnectedToWifi_setsInitialEstimate() {
+ setActiveNetworkInfo(networkInfoWifi);
+ DefaultBandwidthMeter bandwidthMeter =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application)
+ .setInitialBitrateEstimate(C.NETWORK_TYPE_WIFI, 123456789)
+ .build();
+ long initialEstimate = bandwidthMeter.getBitrateEstimate();
+
+ assertThat(initialEstimate).isEqualTo(123456789);
+ }
+
+ @Test
+ public void
+ initialBitrateEstimateOverwrite_forWifi_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() {
+ setActiveNetworkInfo(networkInfo2g);
+ DefaultBandwidthMeter bandwidthMeter =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application)
+ .setInitialBitrateEstimate(C.NETWORK_TYPE_WIFI, 123456789)
+ .build();
+ long initialEstimate = bandwidthMeter.getBitrateEstimate();
+
+ assertThat(initialEstimate).isNotEqualTo(123456789);
+ }
+
+ @Test
+ public void
+ initialBitrateEstimateOverwrite_forEthernet_whileConnectedToEthernet_setsInitialEstimate() {
+ setActiveNetworkInfo(networkInfoEthernet);
+ DefaultBandwidthMeter bandwidthMeter =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application)
+ .setInitialBitrateEstimate(C.NETWORK_TYPE_ETHERNET, 123456789)
+ .build();
+ long initialEstimate = bandwidthMeter.getBitrateEstimate();
+
+ assertThat(initialEstimate).isEqualTo(123456789);
+ }
+
+ @Test
+ public void
+ initialBitrateEstimateOverwrite_forEthernet_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() {
+ setActiveNetworkInfo(networkInfo2g);
+ DefaultBandwidthMeter bandwidthMeter =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application)
+ .setInitialBitrateEstimate(C.NETWORK_TYPE_WIFI, 123456789)
+ .build();
+ long initialEstimate = bandwidthMeter.getBitrateEstimate();
+
+ assertThat(initialEstimate).isNotEqualTo(123456789);
+ }
+
+ @Test
+ public void initialBitrateEstimateOverwrite_for2G_whileConnectedTo2G_setsInitialEstimate() {
+ setActiveNetworkInfo(networkInfo2g);
+ DefaultBandwidthMeter bandwidthMeter =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application)
+ .setInitialBitrateEstimate(C.NETWORK_TYPE_2G, 123456789)
+ .build();
+ long initialEstimate = bandwidthMeter.getBitrateEstimate();
+
+ assertThat(initialEstimate).isEqualTo(123456789);
+ }
+
+ @Test
+ public void
+ initialBitrateEstimateOverwrite_for2G_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() {
+ setActiveNetworkInfo(networkInfoWifi);
+ DefaultBandwidthMeter bandwidthMeter =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application)
+ .setInitialBitrateEstimate(C.NETWORK_TYPE_2G, 123456789)
+ .build();
+ long initialEstimate = bandwidthMeter.getBitrateEstimate();
+
+ assertThat(initialEstimate).isNotEqualTo(123456789);
+ }
+
+ @Test
+ public void initialBitrateEstimateOverwrite_for3G_whileConnectedTo3G_setsInitialEstimate() {
+ setActiveNetworkInfo(networkInfo3g);
+ DefaultBandwidthMeter bandwidthMeter =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application)
+ .setInitialBitrateEstimate(C.NETWORK_TYPE_3G, 123456789)
+ .build();
+ long initialEstimate = bandwidthMeter.getBitrateEstimate();
+
+ assertThat(initialEstimate).isEqualTo(123456789);
+ }
+
+ @Test
+ public void
+ initialBitrateEstimateOverwrite_for3G_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() {
+ setActiveNetworkInfo(networkInfoWifi);
+ DefaultBandwidthMeter bandwidthMeter =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application)
+ .setInitialBitrateEstimate(C.NETWORK_TYPE_3G, 123456789)
+ .build();
+ long initialEstimate = bandwidthMeter.getBitrateEstimate();
+
+ assertThat(initialEstimate).isNotEqualTo(123456789);
+ }
+
+ @Test
+ public void initialBitrateEstimateOverwrite_for4G_whileConnectedTo4G_setsInitialEstimate() {
+ setActiveNetworkInfo(networkInfo4g);
+ DefaultBandwidthMeter bandwidthMeter =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application)
+ .setInitialBitrateEstimate(C.NETWORK_TYPE_4G, 123456789)
+ .build();
+ long initialEstimate = bandwidthMeter.getBitrateEstimate();
+
+ assertThat(initialEstimate).isEqualTo(123456789);
+ }
+
+ @Test
+ public void
+ initialBitrateEstimateOverwrite_for4G_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() {
+ setActiveNetworkInfo(networkInfoWifi);
+ DefaultBandwidthMeter bandwidthMeter =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application)
+ .setInitialBitrateEstimate(C.NETWORK_TYPE_4G, 123456789)
+ .build();
+ long initialEstimate = bandwidthMeter.getBitrateEstimate();
+
+ assertThat(initialEstimate).isNotEqualTo(123456789);
+ }
+
+ @Test
+ public void initialBitrateEstimateOverwrite_forOffline_whileOffline_setsInitialEstimate() {
+ setActiveNetworkInfo(networkInfoOffline);
+ DefaultBandwidthMeter bandwidthMeter =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application)
+ .setInitialBitrateEstimate(C.NETWORK_TYPE_OFFLINE, 123456789)
+ .build();
+ long initialEstimate = bandwidthMeter.getBitrateEstimate();
+
+ assertThat(initialEstimate).isEqualTo(123456789);
+ }
+
+ @Test
+ public void
+ initialBitrateEstimateOverwrite_forOffline_whileConnectedToNetwork_doesNotSetInitialEstimate() {
+ setActiveNetworkInfo(networkInfoWifi);
+ DefaultBandwidthMeter bandwidthMeter =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application)
+ .setInitialBitrateEstimate(C.NETWORK_TYPE_OFFLINE, 123456789)
+ .build();
+ long initialEstimate = bandwidthMeter.getBitrateEstimate();
+
+ assertThat(initialEstimate).isNotEqualTo(123456789);
+ }
+
+ @Test
+ public void initialBitrateEstimateOverwrite_forCountry_usesDefaultValuesForCountry() {
+ setNetworkCountryIso(SLOW_COUNTRY_ISO);
+ DefaultBandwidthMeter bandwidthMeterSlow =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
+
+ setNetworkCountryIso(FAST_COUNTRY_ISO);
+ DefaultBandwidthMeter bandwidthMeterFastWithSlowOverwrite =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application)
+ .setInitialBitrateEstimate(SLOW_COUNTRY_ISO)
+ .build();
+ long initialEstimateFastWithSlowOverwrite =
+ bandwidthMeterFastWithSlowOverwrite.getBitrateEstimate();
+
+ assertThat(initialEstimateFastWithSlowOverwrite).isEqualTo(initialEstimateSlow);
+ }
+
+ @Test
+ public void defaultInitialBitrateEstimate_withoutContext_isReasonable() {
+ DefaultBandwidthMeter bandwidthMeterWithBuilder =
+ new DefaultBandwidthMeter.Builder(/* context= */ null).build();
+ long initialEstimateWithBuilder = bandwidthMeterWithBuilder.getBitrateEstimate();
+
+ DefaultBandwidthMeter bandwidthMeterWithoutBuilder = new DefaultBandwidthMeter();
+ long initialEstimateWithoutBuilder = bandwidthMeterWithoutBuilder.getBitrateEstimate();
+
+ assertThat(initialEstimateWithBuilder).isGreaterThan(100_000L);
+ assertThat(initialEstimateWithBuilder).isLessThan(50_000_000L);
+ assertThat(initialEstimateWithoutBuilder).isGreaterThan(100_000L);
+ assertThat(initialEstimateWithoutBuilder).isLessThan(50_000_000L);
+ }
+
+ @Test
+ public void defaultInitialBitrateEstimate_withoutAccessNetworkStatePermission_isReasonable() {
+ Shadows.shadowOf(RuntimeEnvironment.application).denyPermissions(ACCESS_NETWORK_STATE);
+ DefaultBandwidthMeter bandwidthMeter =
+ new DefaultBandwidthMeter.Builder(RuntimeEnvironment.application).build();
+ long initialEstimate = bandwidthMeter.getBitrateEstimate();
+
+ assertThat(initialEstimate).isGreaterThan(100_000L);
+ assertThat(initialEstimate).isLessThan(50_000_000L);
+ }
+
+ private void setActiveNetworkInfo(NetworkInfo networkInfo) {
+ Shadows.shadowOf(connectivityManager).setActiveNetworkInfo(networkInfo);
+ }
+
+ private void setNetworkCountryIso(String countryIso) {
+ Shadows.shadowOf(telephonyManager).setNetworkCountryIso(countryIso);
+ }
+}