DataSource: Tighten contract to return -1 on premature end-of-input

PiperOrigin-RevId: 363001266
This commit is contained in:
olly 2021-03-15 19:22:49 +00:00 committed by Ian Baker
parent 6c9f9f9def
commit 675b81e5f7
12 changed files with 1340 additions and 99 deletions

View file

@ -33,7 +33,6 @@ import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import com.google.common.base.Predicate;
import com.google.common.net.HttpHeaders;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
@ -478,10 +477,6 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
int read = castNonNull(responseByteStream).read(buffer, offset, readLength);
if (read == -1) {
if (bytesToRead != C.LENGTH_UNSET) {
// End of stream reached having not read sufficient data.
throw new EOFException();
}
return C.RESULT_END_OF_INPUT;
}

View file

@ -29,7 +29,6 @@ import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Util;
import com.google.common.base.Predicate;
import com.google.common.net.HttpHeaders;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
@ -692,10 +691,6 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou
int read = castNonNull(inputStream).read(buffer, offset, readLength);
if (read == -1) {
if (bytesToRead != C.LENGTH_UNSET) {
// End of stream reached having not read sufficient data.
throw new EOFException();
}
return C.RESULT_END_OF_INPUT;
}

View file

@ -108,7 +108,6 @@ public final class ProgressiveDownloader implements Downloader {
new CacheWriter(
dataSource,
dataSpec,
/* allowShortContent= */ false,
/* temporaryBuffer= */ null,
progressListener);
priorityTaskManager = cacheDataSourceFactory.getUpstreamPriorityTaskManager();

View file

@ -472,7 +472,6 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
new CacheWriter(
dataSource,
segment.dataSpec,
/* allowShortContent= */ false,
temporaryBuffer,
progressNotifier);
}

View file

@ -24,7 +24,6 @@ import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.Assertions;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
@ -111,10 +110,6 @@ public final class AssetDataSource extends BaseDataSource {
}
if (bytesRead == -1) {
if (bytesRemaining != C.LENGTH_UNSET) {
// End of stream reached having not read sufficient data.
throw new AssetDataSourceException(new EOFException());
}
return C.RESULT_END_OF_INPUT;
}
if (bytesRemaining != C.LENGTH_UNSET) {

View file

@ -24,7 +24,6 @@ import android.content.res.AssetFileDescriptor;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
@ -147,10 +146,6 @@ public final class ContentDataSource extends BaseDataSource {
}
if (bytesRead == -1) {
if (bytesRemaining != C.LENGTH_UNSET) {
// End of stream reached having not read sufficient data.
throw new ContentDataSourceException(new EOFException());
}
return C.RESULT_END_OF_INPUT;
}
if (bytesRemaining != C.LENGTH_UNSET) {

View file

@ -0,0 +1,720 @@
/*
* Copyright (C) 2021 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 android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.upstream.BandwidthMeter.EventListener.EventDispatcher;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/**
* An experimental {@link BandwidthMeter} that estimates bandwidth by listening to data transfers.
*
* <p>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 ExperimentalBandwidthMeter implements BandwidthMeter, TransferListener {
/**
* Country groups used to determine the default initial bitrate estimate. The group assignment for
* each country is a list for [Wifi, 2G, 3G, 4G, 5G_NSA].
*/
public static final ImmutableListMultimap<String, Integer>
DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS = createInitialBitrateCountryGroupAssignment();
/** Default initial Wifi bitrate estimate in bits per second. */
public static final ImmutableList<Long> DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI =
ImmutableList.of(6_100_000L, 3_900_000L, 2_300_000L, 1_300_000L, 600_000L);
/** Default initial 2G bitrate estimates in bits per second. */
public static final ImmutableList<Long> DEFAULT_INITIAL_BITRATE_ESTIMATES_2G =
ImmutableList.of(230_000L, 159_000L, 142_000L, 127_000L, 112_000L);
/** Default initial 3G bitrate estimates in bits per second. */
public static final ImmutableList<Long> DEFAULT_INITIAL_BITRATE_ESTIMATES_3G =
ImmutableList.of(2_200_000L, 1_300_000L, 940_000L, 760_000L, 520_000L);
/** Default initial 4G bitrate estimates in bits per second. */
public static final ImmutableList<Long> DEFAULT_INITIAL_BITRATE_ESTIMATES_4G =
ImmutableList.of(4_400_000L, 2_300_000L, 1_500_000L, 1_100_000L, 660_000L);
/** Default initial 5G-NSA bitrate estimates in bits per second. */
public static final ImmutableList<Long> DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_NSA =
ImmutableList.of(13_000_000L, 9_100_000L, 6_300_000L, 4_000_000L, 2_000_000L);
@Nullable private static ExperimentalBandwidthMeter singletonInstance;
/**
* 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;
/** Index for the Wifi group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
private static final int COUNTRY_GROUP_INDEX_WIFI = 0;
/** Index for the 2G group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
private static final int COUNTRY_GROUP_INDEX_2G = 1;
/** Index for the 3G group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
private static final int COUNTRY_GROUP_INDEX_3G = 2;
/** Index for the 4G group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
private static final int COUNTRY_GROUP_INDEX_4G = 3;
/** Index for the 5G-NSA group index in {@link #DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS}. */
private static final int COUNTRY_GROUP_INDEX_5G_NSA = 4;
/** Builder for a bandwidth meter. */
public static final class Builder {
@Nullable private final Context context;
private Map<Integer, Long> initialBitrateEstimates;
private Clock clock;
private boolean resetOnNetworkTypeChange;
/**
* Creates a builder with default parameters and without listener.
*
* @param context A context.
*/
public Builder(Context context) {
// Handling of null is for backward compatibility only.
this.context = context == null ? null : context.getApplicationContext();
initialBitrateEstimates = getInitialBitrateEstimatesForCountry(Util.getCountryCode(context));
clock = Clock.DEFAULT;
resetOnNetworkTypeChange = true;
}
/**
* Sets the initial bitrate estimate in bits per second that should be assumed when a bandwidth
* estimate is unavailable.
*
* @param initialBitrateEstimate The initial bitrate estimate in bits per second.
* @return This builder.
*/
public Builder setInitialBitrateEstimate(long initialBitrateEstimate) {
for (Integer networkType : initialBitrateEstimates.keySet()) {
setInitialBitrateEstimate(networkType, initialBitrateEstimate);
}
return this;
}
/**
* Sets the initial bitrate estimate in bits per second 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;
}
/**
* Sets the clock used to estimate bandwidth from data transfers. Should only be set for testing
* purposes.
*
* @param clock The clock used to estimate bandwidth from data transfers.
* @return This builder.
*/
public Builder setClock(Clock clock) {
this.clock = clock;
return this;
}
/**
* Sets whether to reset if the network type changes. The default value is {@code true}.
*
* @param resetOnNetworkTypeChange Whether to reset if the network type changes.
* @return This builder.
*/
public Builder setResetOnNetworkTypeChange(boolean resetOnNetworkTypeChange) {
this.resetOnNetworkTypeChange = resetOnNetworkTypeChange;
return this;
}
/**
* Builds the bandwidth meter.
*
* @return A bandwidth meter with the configured properties.
*/
public ExperimentalBandwidthMeter build() {
return new ExperimentalBandwidthMeter(
context, initialBitrateEstimates, clock, resetOnNetworkTypeChange);
}
private static Map<Integer, Long> getInitialBitrateEstimatesForCountry(String countryCode) {
List<Integer> groupIndices = getCountryGroupIndices(countryCode);
Map<Integer, Long> result = new HashMap<>(/* initialCapacity= */ 6);
result.put(C.NETWORK_TYPE_UNKNOWN, DEFAULT_INITIAL_BITRATE_ESTIMATE);
result.put(
C.NETWORK_TYPE_WIFI,
DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI.get(groupIndices.get(COUNTRY_GROUP_INDEX_WIFI)));
result.put(
C.NETWORK_TYPE_2G,
DEFAULT_INITIAL_BITRATE_ESTIMATES_2G.get(groupIndices.get(COUNTRY_GROUP_INDEX_2G)));
result.put(
C.NETWORK_TYPE_3G,
DEFAULT_INITIAL_BITRATE_ESTIMATES_3G.get(groupIndices.get(COUNTRY_GROUP_INDEX_3G)));
result.put(
C.NETWORK_TYPE_4G,
DEFAULT_INITIAL_BITRATE_ESTIMATES_4G.get(groupIndices.get(COUNTRY_GROUP_INDEX_4G)));
result.put(
C.NETWORK_TYPE_5G,
DEFAULT_INITIAL_BITRATE_ESTIMATES_5G_NSA.get(
groupIndices.get(COUNTRY_GROUP_INDEX_5G_NSA)));
// Assume default Wifi speed for Ethernet to prevent using the slower fallback.
result.put(
C.NETWORK_TYPE_ETHERNET,
DEFAULT_INITIAL_BITRATE_ESTIMATES_WIFI.get(groupIndices.get(COUNTRY_GROUP_INDEX_WIFI)));
return result;
}
private static ImmutableList<Integer> getCountryGroupIndices(String countryCode) {
ImmutableList<Integer> groupIndices = DEFAULT_INITIAL_BITRATE_COUNTRY_GROUPS.get(countryCode);
// Assume median group if not found.
return groupIndices.isEmpty() ? ImmutableList.of(2, 2, 2, 2, 2) : groupIndices;
}
}
/**
* Returns a singleton instance of an {@link ExperimentalBandwidthMeter} with default
* configuration.
*
* @param context A {@link Context}.
* @return The singleton instance.
*/
public static synchronized ExperimentalBandwidthMeter getSingletonInstance(Context context) {
if (singletonInstance == null) {
singletonInstance = new Builder(context).build();
}
return singletonInstance;
}
@Nullable private final Context context;
private final ImmutableMap<Integer, Long> initialBitrateEstimates;
private final EventDispatcher eventDispatcher;
private final Clock clock;
private int streamCount;
private long sampleStartTimeMs;
private long sampleBytesTransferred;
@C.NetworkType private int networkType;
private long bitrateEstimate;
private long lastReportedBitrateEstimate;
private boolean networkTypeOverrideSet;
@C.NetworkType private int networkTypeOverride;
private ExperimentalBandwidthMeter(
@Nullable Context context,
Map<Integer, Long> initialBitrateEstimates,
Clock clock,
boolean resetOnNetworkTypeChange) {
this.context = context == null ? null : context.getApplicationContext();
this.initialBitrateEstimates = ImmutableMap.copyOf(initialBitrateEstimates);
this.eventDispatcher = new EventDispatcher();
this.clock = clock;
// Set the initial network type and bitrate estimate
networkType = context == null ? C.NETWORK_TYPE_UNKNOWN : Util.getNetworkType(context);
bitrateEstimate = getInitialBitrateEstimateForNetworkType(networkType);
// Register to receive connectivity actions if possible.
if (context != null && resetOnNetworkTypeChange) {
ConnectivityActionReceiver connectivityActionReceiver =
ConnectivityActionReceiver.getInstance(context);
connectivityActionReceiver.register(/* bandwidthMeter= */ this);
}
}
/**
* Overrides the network type. Handled in the same way as if the meter had detected a change from
* the current network type to the specified network type internally.
*
* <p>Applications should not normally call this method. It is intended for testing purposes.
*
* @param networkType The overriding network type.
*/
public synchronized void setNetworkTypeOverride(@C.NetworkType int networkType) {
networkTypeOverride = networkType;
networkTypeOverrideSet = true;
onConnectivityAction();
}
@Override
public synchronized long getBitrateEstimate() {
return bitrateEstimate;
}
@Override
public TransferListener getTransferListener() {
return this;
}
@Override
public void addEventListener(Handler eventHandler, EventListener eventListener) {
Assertions.checkNotNull(eventHandler);
Assertions.checkNotNull(eventListener);
eventDispatcher.addListener(eventHandler, eventListener);
}
@Override
public void removeEventListener(EventListener eventListener) {
eventDispatcher.removeListener(eventListener);
}
@Override
public void onTransferInitializing(DataSource source, DataSpec dataSpec, boolean isNetwork) {
// TODO: Track time for time-to-response estimation.
}
@Override
public synchronized void onTransferStart(
DataSource source, DataSpec dataSpec, boolean isNetwork) {
if (!isTransferAtFullNetworkSpeed(dataSpec, isNetwork)) {
return;
}
if (streamCount == 0) {
sampleStartTimeMs = clock.elapsedRealtime();
}
streamCount++;
// TODO: Track time for time-to-response estimation.
}
@Override
public synchronized void onBytesTransferred(
DataSource source, DataSpec dataSpec, boolean isNetwork, int bytes) {
if (!isTransferAtFullNetworkSpeed(dataSpec, isNetwork)) {
return;
}
sampleBytesTransferred += bytes;
}
@Override
public synchronized void onTransferEnd(DataSource source, DataSpec dataSpec, boolean isNetwork) {
if (!isTransferAtFullNetworkSpeed(dataSpec, isNetwork)) {
return;
}
Assertions.checkState(streamCount > 0);
long nowMs = clock.elapsedRealtime();
int sampleElapsedTimeMs = (int) (nowMs - sampleStartTimeMs);
if (sampleElapsedTimeMs > 0) {
// TODO: Add heuristic for bandwidth estimation.
bitrateEstimate = (long) (sampleBytesTransferred * 8000f) / sampleElapsedTimeMs;
maybeNotifyBandwidthSample(sampleElapsedTimeMs, sampleBytesTransferred, bitrateEstimate);
sampleStartTimeMs = nowMs;
sampleBytesTransferred = 0;
} // Else any sample bytes transferred will be carried forward into the next sample.
streamCount--;
}
private synchronized void onConnectivityAction() {
int networkType =
networkTypeOverrideSet
? networkTypeOverride
: (context == null ? C.NETWORK_TYPE_UNKNOWN : Util.getNetworkType(context));
if (this.networkType == networkType) {
return;
}
this.networkType = networkType;
if (networkType == C.NETWORK_TYPE_OFFLINE
|| networkType == C.NETWORK_TYPE_UNKNOWN
|| networkType == C.NETWORK_TYPE_OTHER) {
// It's better not to reset the bandwidth meter for these network types.
return;
}
// Reset the bitrate estimate and report it, along with any bytes transferred.
this.bitrateEstimate = getInitialBitrateEstimateForNetworkType(networkType);
long nowMs = clock.elapsedRealtime();
int sampleElapsedTimeMs = streamCount > 0 ? (int) (nowMs - sampleStartTimeMs) : 0;
maybeNotifyBandwidthSample(sampleElapsedTimeMs, sampleBytesTransferred, bitrateEstimate);
// Reset the remainder of the state.
sampleStartTimeMs = nowMs;
sampleBytesTransferred = 0;
}
private void maybeNotifyBandwidthSample(
int elapsedMs, long bytesTransferred, long bitrateEstimate) {
if (elapsedMs == 0 && bytesTransferred == 0 && bitrateEstimate == lastReportedBitrateEstimate) {
return;
}
lastReportedBitrateEstimate = bitrateEstimate;
eventDispatcher.bandwidthSample(elapsedMs, bytesTransferred, bitrateEstimate);
}
private long getInitialBitrateEstimateForNetworkType(@C.NetworkType int networkType) {
Long initialBitrateEstimate = initialBitrateEstimates.get(networkType);
if (initialBitrateEstimate == null) {
initialBitrateEstimate = initialBitrateEstimates.get(C.NETWORK_TYPE_UNKNOWN);
}
if (initialBitrateEstimate == null) {
initialBitrateEstimate = DEFAULT_INITIAL_BITRATE_ESTIMATE;
}
return initialBitrateEstimate;
}
private static boolean isTransferAtFullNetworkSpeed(DataSpec dataSpec, boolean isNetwork) {
return isNetwork && !dataSpec.isFlagSet(DataSpec.FLAG_MIGHT_NOT_USE_FULL_NETWORK_SPEED);
}
/*
* Note: This class only holds a weak reference to bandwidth meter instances. It should not
* be made non-static, since doing so adds a strong reference (i.e.,
* ExperimentalBandwidthMeter.this).
*/
private static class ConnectivityActionReceiver extends BroadcastReceiver {
private static @MonotonicNonNull ConnectivityActionReceiver staticInstance;
private final Handler mainHandler;
private final ArrayList<WeakReference<ExperimentalBandwidthMeter>> bandwidthMeters;
public static synchronized ConnectivityActionReceiver getInstance(Context context) {
if (staticInstance == null) {
staticInstance = new ConnectivityActionReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(staticInstance, filter);
}
return staticInstance;
}
private ConnectivityActionReceiver() {
mainHandler = new Handler(Looper.getMainLooper());
bandwidthMeters = new ArrayList<>();
}
public synchronized void register(ExperimentalBandwidthMeter bandwidthMeter) {
removeClearedReferences();
bandwidthMeters.add(new WeakReference<>(bandwidthMeter));
// Simulate an initial update on the main thread (like the sticky broadcast we'd receive if
// we were to register a separate broadcast receiver for each bandwidth meter).
mainHandler.post(() -> updateBandwidthMeter(bandwidthMeter));
}
@Override
public synchronized void onReceive(Context context, Intent intent) {
if (isInitialStickyBroadcast()) {
return;
}
removeClearedReferences();
for (int i = 0; i < bandwidthMeters.size(); i++) {
WeakReference<ExperimentalBandwidthMeter> bandwidthMeterReference = bandwidthMeters.get(i);
ExperimentalBandwidthMeter bandwidthMeter = bandwidthMeterReference.get();
if (bandwidthMeter != null) {
updateBandwidthMeter(bandwidthMeter);
}
}
}
private void updateBandwidthMeter(ExperimentalBandwidthMeter bandwidthMeter) {
bandwidthMeter.onConnectivityAction();
}
private void removeClearedReferences() {
for (int i = bandwidthMeters.size() - 1; i >= 0; i--) {
WeakReference<ExperimentalBandwidthMeter> bandwidthMeterReference = bandwidthMeters.get(i);
ExperimentalBandwidthMeter bandwidthMeter = bandwidthMeterReference.get();
if (bandwidthMeter == null) {
bandwidthMeters.remove(i);
}
}
}
}
private static ImmutableListMultimap<String, Integer>
createInitialBitrateCountryGroupAssignment() {
ImmutableListMultimap.Builder<String, Integer> countryGroupAssignment =
ImmutableListMultimap.builder();
countryGroupAssignment.putAll("AD", 1, 2, 0, 0, 2);
countryGroupAssignment.putAll("AE", 1, 4, 4, 4, 2);
countryGroupAssignment.putAll("AF", 4, 4, 4, 4, 2);
countryGroupAssignment.putAll("AG", 4, 2, 1, 4, 2);
countryGroupAssignment.putAll("AI", 1, 2, 2, 2, 2);
countryGroupAssignment.putAll("AL", 1, 1, 1, 1, 2);
countryGroupAssignment.putAll("AM", 2, 2, 1, 3, 2);
countryGroupAssignment.putAll("AO", 3, 4, 3, 1, 2);
countryGroupAssignment.putAll("AR", 2, 4, 2, 1, 2);
countryGroupAssignment.putAll("AS", 2, 2, 3, 3, 2);
countryGroupAssignment.putAll("AT", 0, 2, 0, 0, 0);
countryGroupAssignment.putAll("AU", 0, 2, 0, 1, 1);
countryGroupAssignment.putAll("AW", 1, 2, 0, 4, 2);
countryGroupAssignment.putAll("AX", 0, 2, 2, 2, 2);
countryGroupAssignment.putAll("AZ", 3, 3, 3, 4, 2);
countryGroupAssignment.putAll("BA", 1, 1, 0, 1, 2);
countryGroupAssignment.putAll("BB", 0, 2, 0, 0, 2);
countryGroupAssignment.putAll("BD", 2, 0, 3, 3, 2);
countryGroupAssignment.putAll("BE", 0, 0, 2, 3, 2);
countryGroupAssignment.putAll("BF", 4, 4, 4, 2, 2);
countryGroupAssignment.putAll("BG", 0, 1, 0, 0, 2);
countryGroupAssignment.putAll("BH", 1, 0, 2, 4, 3);
countryGroupAssignment.putAll("BI", 4, 4, 4, 4, 2);
countryGroupAssignment.putAll("BJ", 4, 4, 4, 4, 2);
countryGroupAssignment.putAll("BL", 1, 2, 2, 2, 2);
countryGroupAssignment.putAll("BM", 0, 2, 0, 0, 2);
countryGroupAssignment.putAll("BN", 3, 2, 1, 0, 2);
countryGroupAssignment.putAll("BO", 1, 2, 4, 2, 2);
countryGroupAssignment.putAll("BQ", 1, 2, 1, 3, 2);
countryGroupAssignment.putAll("BR", 2, 4, 2, 2, 3);
countryGroupAssignment.putAll("BS", 2, 2, 1, 3, 2);
countryGroupAssignment.putAll("BT", 3, 0, 3, 2, 2);
countryGroupAssignment.putAll("BW", 3, 4, 1, 1, 2);
countryGroupAssignment.putAll("BY", 1, 1, 1, 2, 2);
countryGroupAssignment.putAll("BZ", 2, 2, 2, 2, 2);
countryGroupAssignment.putAll("CA", 0, 3, 1, 2, 4);
countryGroupAssignment.putAll("CD", 4, 3, 2, 1, 2);
countryGroupAssignment.putAll("CF", 4, 2, 3, 2, 2);
countryGroupAssignment.putAll("CG", 3, 4, 2, 2, 2);
countryGroupAssignment.putAll("CH", 0, 0, 0, 0, 2);
countryGroupAssignment.putAll("CI", 3, 3, 3, 3, 2);
countryGroupAssignment.putAll("CK", 2, 2, 3, 0, 2);
countryGroupAssignment.putAll("CL", 1, 1, 2, 2, 2);
countryGroupAssignment.putAll("CM", 3, 4, 3, 3, 2);
countryGroupAssignment.putAll("CN", 2, 2, 2, 1, 4);
countryGroupAssignment.putAll("CO", 2, 3, 4, 2, 2);
countryGroupAssignment.putAll("CR", 2, 3, 4, 4, 2);
countryGroupAssignment.putAll("CU", 4, 4, 2, 2, 2);
countryGroupAssignment.putAll("CV", 2, 3, 1, 0, 2);
countryGroupAssignment.putAll("CW", 1, 2, 0, 0, 2);
countryGroupAssignment.putAll("CY", 1, 1, 0, 0, 2);
countryGroupAssignment.putAll("CZ", 0, 1, 0, 0, 1);
countryGroupAssignment.putAll("DE", 0, 0, 1, 1, 0);
countryGroupAssignment.putAll("DJ", 4, 0, 4, 4, 2);
countryGroupAssignment.putAll("DK", 0, 0, 1, 0, 0);
countryGroupAssignment.putAll("DM", 1, 2, 2, 2, 2);
countryGroupAssignment.putAll("DO", 3, 4, 4, 4, 2);
countryGroupAssignment.putAll("DZ", 3, 3, 4, 4, 2);
countryGroupAssignment.putAll("EC", 2, 4, 3, 2, 2);
countryGroupAssignment.putAll("EE", 0, 1, 0, 0, 2);
countryGroupAssignment.putAll("EG", 3, 4, 3, 3, 2);
countryGroupAssignment.putAll("EH", 2, 2, 2, 2, 2);
countryGroupAssignment.putAll("ER", 4, 2, 2, 2, 2);
countryGroupAssignment.putAll("ES", 0, 1, 1, 1, 2);
countryGroupAssignment.putAll("ET", 4, 4, 4, 1, 2);
countryGroupAssignment.putAll("FI", 0, 0, 0, 0, 0);
countryGroupAssignment.putAll("FJ", 3, 0, 2, 2, 2);
countryGroupAssignment.putAll("FK", 4, 2, 2, 2, 2);
countryGroupAssignment.putAll("FM", 3, 2, 4, 4, 2);
countryGroupAssignment.putAll("FO", 1, 2, 0, 1, 2);
countryGroupAssignment.putAll("FR", 1, 1, 2, 0, 1);
countryGroupAssignment.putAll("GA", 3, 4, 1, 1, 2);
countryGroupAssignment.putAll("GB", 0, 0, 1, 1, 1);
countryGroupAssignment.putAll("GD", 1, 2, 2, 2, 2);
countryGroupAssignment.putAll("GE", 1, 1, 1, 3, 2);
countryGroupAssignment.putAll("GF", 2, 2, 2, 3, 2);
countryGroupAssignment.putAll("GG", 1, 2, 0, 0, 2);
countryGroupAssignment.putAll("GH", 3, 1, 3, 2, 2);
countryGroupAssignment.putAll("GI", 0, 2, 2, 0, 2);
countryGroupAssignment.putAll("GL", 1, 2, 0, 0, 2);
countryGroupAssignment.putAll("GM", 4, 3, 2, 4, 2);
countryGroupAssignment.putAll("GN", 3, 3, 4, 2, 2);
countryGroupAssignment.putAll("GP", 2, 1, 2, 3, 2);
countryGroupAssignment.putAll("GQ", 4, 2, 2, 4, 2);
countryGroupAssignment.putAll("GR", 1, 2, 0, 1, 2);
countryGroupAssignment.putAll("GT", 3, 2, 2, 1, 2);
countryGroupAssignment.putAll("GU", 1, 2, 3, 4, 2);
countryGroupAssignment.putAll("GW", 4, 4, 4, 4, 2);
countryGroupAssignment.putAll("GY", 3, 3, 3, 4, 2);
countryGroupAssignment.putAll("HK", 0, 1, 2, 3, 2);
countryGroupAssignment.putAll("HN", 3, 1, 3, 3, 2);
countryGroupAssignment.putAll("HR", 1, 1, 0, 0, 3);
countryGroupAssignment.putAll("HT", 4, 4, 4, 4, 2);
countryGroupAssignment.putAll("HU", 0, 0, 0, 0, 1);
countryGroupAssignment.putAll("ID", 3, 2, 3, 3, 2);
countryGroupAssignment.putAll("IE", 0, 0, 1, 1, 3);
countryGroupAssignment.putAll("IL", 1, 0, 2, 3, 4);
countryGroupAssignment.putAll("IM", 0, 2, 0, 1, 2);
countryGroupAssignment.putAll("IN", 2, 1, 3, 3, 2);
countryGroupAssignment.putAll("IO", 4, 2, 2, 4, 2);
countryGroupAssignment.putAll("IQ", 3, 3, 4, 4, 2);
countryGroupAssignment.putAll("IR", 3, 2, 3, 2, 2);
countryGroupAssignment.putAll("IS", 0, 2, 0, 0, 2);
countryGroupAssignment.putAll("IT", 0, 4, 1, 1, 2);
countryGroupAssignment.putAll("JE", 2, 2, 1, 2, 2);
countryGroupAssignment.putAll("JM", 3, 3, 4, 4, 2);
countryGroupAssignment.putAll("JO", 2, 2, 1, 1, 2);
countryGroupAssignment.putAll("JP", 0, 0, 0, 0, 3);
countryGroupAssignment.putAll("KE", 3, 4, 2, 2, 2);
countryGroupAssignment.putAll("KG", 2, 0, 1, 1, 2);
countryGroupAssignment.putAll("KH", 1, 0, 4, 3, 2);
countryGroupAssignment.putAll("KI", 4, 2, 4, 3, 2);
countryGroupAssignment.putAll("KM", 4, 3, 3, 3, 2);
countryGroupAssignment.putAll("KN", 1, 2, 2, 2, 2);
countryGroupAssignment.putAll("KP", 4, 2, 2, 2, 2);
countryGroupAssignment.putAll("KR", 0, 0, 1, 3, 1);
countryGroupAssignment.putAll("KW", 1, 3, 0, 0, 0);
countryGroupAssignment.putAll("KY", 1, 2, 0, 2, 2);
countryGroupAssignment.putAll("KZ", 2, 2, 2, 3, 2);
countryGroupAssignment.putAll("LA", 2, 2, 1, 1, 2);
countryGroupAssignment.putAll("LB", 3, 2, 0, 0, 2);
countryGroupAssignment.putAll("LC", 1, 2, 0, 1, 2);
countryGroupAssignment.putAll("LI", 0, 2, 2, 2, 2);
countryGroupAssignment.putAll("LK", 2, 0, 2, 3, 2);
countryGroupAssignment.putAll("LR", 3, 4, 4, 3, 2);
countryGroupAssignment.putAll("LS", 3, 3, 2, 3, 2);
countryGroupAssignment.putAll("LT", 0, 0, 0, 0, 2);
countryGroupAssignment.putAll("LU", 1, 0, 1, 1, 2);
countryGroupAssignment.putAll("LV", 0, 0, 0, 0, 2);
countryGroupAssignment.putAll("LY", 4, 2, 4, 4, 2);
countryGroupAssignment.putAll("MA", 3, 2, 2, 1, 2);
countryGroupAssignment.putAll("MC", 0, 2, 0, 0, 2);
countryGroupAssignment.putAll("MD", 1, 2, 0, 0, 2);
countryGroupAssignment.putAll("ME", 1, 2, 0, 1, 2);
countryGroupAssignment.putAll("MF", 1, 2, 1, 1, 2);
countryGroupAssignment.putAll("MG", 3, 4, 2, 2, 2);
countryGroupAssignment.putAll("MH", 4, 2, 2, 4, 2);
countryGroupAssignment.putAll("MK", 1, 1, 0, 0, 2);
countryGroupAssignment.putAll("ML", 4, 4, 2, 2, 2);
countryGroupAssignment.putAll("MM", 2, 3, 3, 3, 2);
countryGroupAssignment.putAll("MN", 2, 4, 1, 2, 2);
countryGroupAssignment.putAll("MO", 0, 2, 4, 4, 2);
countryGroupAssignment.putAll("MP", 0, 2, 2, 2, 2);
countryGroupAssignment.putAll("MQ", 2, 2, 2, 3, 2);
countryGroupAssignment.putAll("MR", 3, 0, 4, 3, 2);
countryGroupAssignment.putAll("MS", 1, 2, 2, 2, 2);
countryGroupAssignment.putAll("MT", 0, 2, 0, 0, 2);
countryGroupAssignment.putAll("MU", 3, 1, 1, 2, 2);
countryGroupAssignment.putAll("MV", 4, 3, 3, 4, 2);
countryGroupAssignment.putAll("MW", 4, 2, 1, 0, 2);
countryGroupAssignment.putAll("MX", 2, 4, 3, 4, 2);
countryGroupAssignment.putAll("MY", 1, 0, 3, 2, 2);
countryGroupAssignment.putAll("MZ", 3, 3, 2, 1, 2);
countryGroupAssignment.putAll("NA", 4, 3, 3, 2, 2);
countryGroupAssignment.putAll("NC", 2, 0, 3, 4, 2);
countryGroupAssignment.putAll("NE", 4, 4, 4, 4, 2);
countryGroupAssignment.putAll("NF", 2, 2, 2, 2, 2);
countryGroupAssignment.putAll("NG", 3, 3, 2, 2, 2);
countryGroupAssignment.putAll("NI", 2, 1, 4, 4, 2);
countryGroupAssignment.putAll("NL", 0, 2, 3, 2, 0);
countryGroupAssignment.putAll("NO", 0, 1, 2, 0, 0);
countryGroupAssignment.putAll("NP", 2, 0, 4, 2, 2);
countryGroupAssignment.putAll("NR", 3, 2, 2, 1, 2);
countryGroupAssignment.putAll("NU", 4, 2, 2, 2, 2);
countryGroupAssignment.putAll("NZ", 0, 2, 1, 2, 4);
countryGroupAssignment.putAll("OM", 2, 2, 1, 3, 2);
countryGroupAssignment.putAll("PA", 1, 3, 3, 3, 2);
countryGroupAssignment.putAll("PE", 2, 3, 4, 4, 2);
countryGroupAssignment.putAll("PF", 2, 2, 2, 1, 2);
countryGroupAssignment.putAll("PG", 4, 4, 3, 2, 2);
countryGroupAssignment.putAll("PH", 2, 1, 3, 3, 4);
countryGroupAssignment.putAll("PK", 3, 2, 3, 3, 2);
countryGroupAssignment.putAll("PL", 1, 0, 1, 2, 3);
countryGroupAssignment.putAll("PM", 0, 2, 2, 2, 2);
countryGroupAssignment.putAll("PR", 2, 1, 2, 2, 4);
countryGroupAssignment.putAll("PS", 3, 3, 2, 2, 2);
countryGroupAssignment.putAll("PT", 0, 1, 1, 0, 2);
countryGroupAssignment.putAll("PW", 1, 2, 4, 0, 2);
countryGroupAssignment.putAll("PY", 2, 0, 3, 2, 2);
countryGroupAssignment.putAll("QA", 2, 3, 1, 2, 3);
countryGroupAssignment.putAll("RE", 1, 0, 2, 2, 2);
countryGroupAssignment.putAll("RO", 0, 1, 0, 1, 1);
countryGroupAssignment.putAll("RS", 1, 2, 0, 0, 2);
countryGroupAssignment.putAll("RU", 0, 1, 0, 1, 2);
countryGroupAssignment.putAll("RW", 3, 3, 4, 1, 2);
countryGroupAssignment.putAll("SA", 2, 2, 2, 1, 2);
countryGroupAssignment.putAll("SB", 4, 2, 3, 2, 2);
countryGroupAssignment.putAll("SC", 4, 1, 1, 3, 2);
countryGroupAssignment.putAll("SD", 4, 4, 4, 4, 2);
countryGroupAssignment.putAll("SE", 0, 0, 0, 0, 0);
countryGroupAssignment.putAll("SG", 1, 0, 1, 2, 3);
countryGroupAssignment.putAll("SH", 4, 2, 2, 2, 2);
countryGroupAssignment.putAll("SI", 0, 0, 0, 0, 2);
countryGroupAssignment.putAll("SJ", 2, 2, 2, 2, 2);
countryGroupAssignment.putAll("SK", 0, 1, 0, 0, 2);
countryGroupAssignment.putAll("SL", 4, 3, 4, 0, 2);
countryGroupAssignment.putAll("SM", 0, 2, 2, 2, 2);
countryGroupAssignment.putAll("SN", 4, 4, 4, 4, 2);
countryGroupAssignment.putAll("SO", 3, 3, 3, 4, 2);
countryGroupAssignment.putAll("SR", 3, 2, 2, 2, 2);
countryGroupAssignment.putAll("SS", 4, 4, 3, 3, 2);
countryGroupAssignment.putAll("ST", 2, 2, 1, 2, 2);
countryGroupAssignment.putAll("SV", 2, 1, 4, 3, 2);
countryGroupAssignment.putAll("SX", 2, 2, 1, 0, 2);
countryGroupAssignment.putAll("SY", 4, 3, 3, 2, 2);
countryGroupAssignment.putAll("SZ", 4, 3, 2, 4, 2);
countryGroupAssignment.putAll("TC", 2, 2, 2, 0, 2);
countryGroupAssignment.putAll("TD", 4, 3, 4, 4, 2);
countryGroupAssignment.putAll("TG", 3, 2, 2, 4, 2);
countryGroupAssignment.putAll("TH", 0, 3, 2, 3, 2);
countryGroupAssignment.putAll("TJ", 4, 4, 4, 4, 2);
countryGroupAssignment.putAll("TL", 4, 0, 4, 4, 2);
countryGroupAssignment.putAll("TM", 4, 2, 4, 3, 2);
countryGroupAssignment.putAll("TN", 2, 2, 1, 2, 2);
countryGroupAssignment.putAll("TO", 3, 2, 4, 3, 2);
countryGroupAssignment.putAll("TR", 1, 2, 0, 1, 2);
countryGroupAssignment.putAll("TT", 1, 4, 0, 1, 2);
countryGroupAssignment.putAll("TV", 3, 2, 2, 4, 2);
countryGroupAssignment.putAll("TW", 0, 0, 0, 0, 1);
countryGroupAssignment.putAll("TZ", 3, 3, 3, 2, 2);
countryGroupAssignment.putAll("UA", 0, 3, 1, 1, 2);
countryGroupAssignment.putAll("UG", 3, 2, 3, 3, 2);
countryGroupAssignment.putAll("US", 1, 1, 2, 2, 4);
countryGroupAssignment.putAll("UY", 2, 1, 1, 1, 2);
countryGroupAssignment.putAll("UZ", 2, 1, 3, 4, 2);
countryGroupAssignment.putAll("VC", 1, 2, 2, 2, 2);
countryGroupAssignment.putAll("VE", 4, 4, 4, 4, 2);
countryGroupAssignment.putAll("VG", 2, 2, 1, 1, 2);
countryGroupAssignment.putAll("VI", 1, 2, 1, 2, 2);
countryGroupAssignment.putAll("VN", 0, 1, 3, 4, 2);
countryGroupAssignment.putAll("VU", 4, 0, 3, 1, 2);
countryGroupAssignment.putAll("WF", 4, 2, 2, 2, 2);
countryGroupAssignment.putAll("WS", 3, 1, 3, 1, 2);
countryGroupAssignment.putAll("XK", 0, 1, 1, 1, 2);
countryGroupAssignment.putAll("YE", 4, 4, 4, 3, 2);
countryGroupAssignment.putAll("YT", 4, 2, 2, 3, 2);
countryGroupAssignment.putAll("ZA", 3, 3, 2, 1, 2);
countryGroupAssignment.putAll("ZM", 3, 2, 3, 3, 2);
countryGroupAssignment.putAll("ZW", 3, 2, 4, 3, 2);
return countryGroupAssignment.build();
}
}

View file

@ -23,7 +23,6 @@ import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.util.PriorityTaskManager;
import com.google.android.exoplayer2.util.PriorityTaskManager.PriorityTooLowException;
import com.google.android.exoplayer2.util.Util;
import java.io.EOFException;
import java.io.IOException;
import java.io.InterruptedIOException;
@ -51,7 +50,6 @@ public final class CacheWriter {
private final CacheDataSource dataSource;
private final Cache cache;
private final DataSpec dataSpec;
private final boolean allowShortContent;
private final String cacheKey;
private final byte[] temporaryBuffer;
@Nullable private final ProgressListener progressListener;
@ -65,10 +63,6 @@ public final class CacheWriter {
/**
* @param dataSource A {@link CacheDataSource} that writes to the target cache.
* @param dataSpec Defines the data to be written.
* @param allowShortContent Whether it's allowed for the content to end before the request as
* defined by the {@link DataSpec}. If {@code true} and the request exceeds the length of the
* content, then the content will be cached to the end. If {@code false} and the request
* exceeds the length of the content, {@link #cache} will throw an {@link IOException}.
* @param temporaryBuffer A temporary buffer to be used during caching, or {@code null} if the
* writer should instantiate its own internal temporary buffer.
* @param progressListener An optional progress listener.
@ -76,13 +70,11 @@ public final class CacheWriter {
public CacheWriter(
CacheDataSource dataSource,
DataSpec dataSpec,
boolean allowShortContent,
@Nullable byte[] temporaryBuffer,
@Nullable ProgressListener progressListener) {
this.dataSource = dataSource;
this.cache = dataSource.getCache();
this.dataSpec = dataSpec;
this.allowShortContent = allowShortContent;
this.temporaryBuffer =
temporaryBuffer == null ? new byte[DEFAULT_BUFFER_SIZE_BYTES] : temporaryBuffer;
this.progressListener = progressListener;
@ -143,14 +135,6 @@ public final class CacheWriter {
nextPosition += readBlockToCache(nextPosition, nextRequestLength);
}
}
// TODO: Remove allowShortContent parameter, this code block, and return the number of bytes
// cached. The caller can then check whether fewer bytes were cached than were requested.
if (!allowShortContent
&& dataSpec.length != C.LENGTH_UNSET
&& nextPosition != dataSpec.position + dataSpec.length) {
throw new EOFException();
}
}
/**
@ -176,9 +160,11 @@ public final class CacheWriter {
isDataSourceOpen = true;
} catch (IOException e) {
Util.closeQuietly(dataSource);
if (allowShortContent
&& isLastBlock
&& DataSourceException.isCausedByPositionOutOfRange(e)) {
// TODO: This exception handling may be required for interop with current HttpDataSource
// implementations that (incorrectly) throw a position-out-of-range when opened exactly one
// byte beyond the end of the resource. It should be removed when the HttpDataSource
// implementations are fixed.
if (isLastBlock && DataSourceException.isCausedByPositionOutOfRange(e)) {
// The length of the request exceeds the length of the content. If we allow shorter
// content and are reading the last block, fall through and try again with an unbounded
// request to read up to the end of the content.

View file

@ -0,0 +1,583 @@
/*
* Copyright (C) 2021 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.net.NetworkInfo.State.CONNECTED;
import static android.net.NetworkInfo.State.DISCONNECTED;
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.net.Uri;
import android.telephony.TelephonyManager;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.testutil.FakeClock;
import com.google.android.exoplayer2.testutil.FakeDataSource;
import java.util.Random;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Shadows;
import org.robolectric.shadows.ShadowNetworkInfo;
/** Unit test for {@link ExperimentalBandwidthMeter}. */
@RunWith(AndroidJUnit4.class)
public final class ExperimentalBandwidthMeterTest {
private static final int SIMULATED_TRANSFER_COUNT = 100;
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)
ApplicationProvider.getApplicationContext()
.getSystemService(Context.CONNECTIVITY_SERVICE);
telephonyManager =
(TelephonyManager)
ApplicationProvider.getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
Shadows.shadowOf(telephonyManager).setNetworkCountryIso(FAST_COUNTRY_ISO);
networkInfoOffline =
ShadowNetworkInfo.newInstance(
DetailedState.DISCONNECTED,
ConnectivityManager.TYPE_WIFI,
/* subType= */ 0,
/* isAvailable= */ false,
DISCONNECTED);
networkInfoWifi =
ShadowNetworkInfo.newInstance(
DetailedState.CONNECTED,
ConnectivityManager.TYPE_WIFI,
/* subType= */ 0,
/* isAvailable= */ true,
CONNECTED);
networkInfo2g =
ShadowNetworkInfo.newInstance(
DetailedState.CONNECTED,
ConnectivityManager.TYPE_MOBILE,
TelephonyManager.NETWORK_TYPE_GPRS,
/* isAvailable= */ true,
CONNECTED);
networkInfo3g =
ShadowNetworkInfo.newInstance(
DetailedState.CONNECTED,
ConnectivityManager.TYPE_MOBILE,
TelephonyManager.NETWORK_TYPE_HSDPA,
/* isAvailable= */ true,
CONNECTED);
networkInfo4g =
ShadowNetworkInfo.newInstance(
DetailedState.CONNECTED,
ConnectivityManager.TYPE_MOBILE,
TelephonyManager.NETWORK_TYPE_LTE,
/* isAvailable= */ true,
CONNECTED);
networkInfoEthernet =
ShadowNetworkInfo.newInstance(
DetailedState.CONNECTED,
ConnectivityManager.TYPE_ETHERNET,
/* subType= */ 0,
/* isAvailable= */ true,
CONNECTED);
}
@Test
public void defaultInitialBitrateEstimate_forWifi_isGreaterThanEstimateFor2G() {
setActiveNetworkInfo(networkInfoWifi);
ExperimentalBandwidthMeter bandwidthMeterWifi =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimateWifi = bandwidthMeterWifi.getBitrateEstimate();
setActiveNetworkInfo(networkInfo2g);
ExperimentalBandwidthMeter bandwidthMeter2g =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimate2g = bandwidthMeter2g.getBitrateEstimate();
assertThat(initialEstimateWifi).isGreaterThan(initialEstimate2g);
}
@Test
public void defaultInitialBitrateEstimate_forWifi_isGreaterThanEstimateFor3G() {
setActiveNetworkInfo(networkInfoWifi);
ExperimentalBandwidthMeter bandwidthMeterWifi =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimateWifi = bandwidthMeterWifi.getBitrateEstimate();
setActiveNetworkInfo(networkInfo3g);
ExperimentalBandwidthMeter bandwidthMeter3g =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimate3g = bandwidthMeter3g.getBitrateEstimate();
assertThat(initialEstimateWifi).isGreaterThan(initialEstimate3g);
}
@Test
public void defaultInitialBitrateEstimate_forEthernet_isGreaterThanEstimateFor2G() {
setActiveNetworkInfo(networkInfoEthernet);
ExperimentalBandwidthMeter bandwidthMeterEthernet =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimateEthernet = bandwidthMeterEthernet.getBitrateEstimate();
setActiveNetworkInfo(networkInfo2g);
ExperimentalBandwidthMeter bandwidthMeter2g =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimate2g = bandwidthMeter2g.getBitrateEstimate();
assertThat(initialEstimateEthernet).isGreaterThan(initialEstimate2g);
}
@Test
public void defaultInitialBitrateEstimate_forEthernet_isGreaterThanEstimateFor3G() {
setActiveNetworkInfo(networkInfoEthernet);
ExperimentalBandwidthMeter bandwidthMeterEthernet =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimateEthernet = bandwidthMeterEthernet.getBitrateEstimate();
setActiveNetworkInfo(networkInfo3g);
ExperimentalBandwidthMeter bandwidthMeter3g =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimate3g = bandwidthMeter3g.getBitrateEstimate();
assertThat(initialEstimateEthernet).isGreaterThan(initialEstimate3g);
}
@Test
public void defaultInitialBitrateEstimate_for4G_isGreaterThanEstimateFor2G() {
setActiveNetworkInfo(networkInfo4g);
ExperimentalBandwidthMeter bandwidthMeter4g =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimate4g = bandwidthMeter4g.getBitrateEstimate();
setActiveNetworkInfo(networkInfo2g);
ExperimentalBandwidthMeter bandwidthMeter2g =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimate2g = bandwidthMeter2g.getBitrateEstimate();
assertThat(initialEstimate4g).isGreaterThan(initialEstimate2g);
}
@Test
public void defaultInitialBitrateEstimate_for4G_isGreaterThanEstimateFor3G() {
setActiveNetworkInfo(networkInfo4g);
ExperimentalBandwidthMeter bandwidthMeter4g =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimate4g = bandwidthMeter4g.getBitrateEstimate();
setActiveNetworkInfo(networkInfo3g);
ExperimentalBandwidthMeter bandwidthMeter3g =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimate3g = bandwidthMeter3g.getBitrateEstimate();
assertThat(initialEstimate4g).isGreaterThan(initialEstimate3g);
}
@Test
public void defaultInitialBitrateEstimate_for3G_isGreaterThanEstimateFor2G() {
setActiveNetworkInfo(networkInfo3g);
ExperimentalBandwidthMeter bandwidthMeter3g =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimate3g = bandwidthMeter3g.getBitrateEstimate();
setActiveNetworkInfo(networkInfo2g);
ExperimentalBandwidthMeter bandwidthMeter2g =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimate2g = bandwidthMeter2g.getBitrateEstimate();
assertThat(initialEstimate3g).isGreaterThan(initialEstimate2g);
}
@Test
public void defaultInitialBitrateEstimate_forOffline_isReasonable() {
setActiveNetworkInfo(networkInfoOffline);
ExperimentalBandwidthMeter bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).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);
ExperimentalBandwidthMeter bandwidthMeterFast =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimateFast = bandwidthMeterFast.getBitrateEstimate();
setNetworkCountryIso(SLOW_COUNTRY_ISO);
ExperimentalBandwidthMeter bandwidthMeterSlow =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow);
}
@Test
public void
defaultInitialBitrateEstimate_forEthernet_forFastCountry_isGreaterThanEstimateForSlowCountry() {
setActiveNetworkInfo(networkInfoEthernet);
setNetworkCountryIso(FAST_COUNTRY_ISO);
ExperimentalBandwidthMeter bandwidthMeterFast =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimateFast = bandwidthMeterFast.getBitrateEstimate();
setNetworkCountryIso(SLOW_COUNTRY_ISO);
ExperimentalBandwidthMeter bandwidthMeterSlow =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow);
}
@Test
public void
defaultInitialBitrateEstimate_for2G_forFastCountry_isGreaterThanEstimateForSlowCountry() {
setActiveNetworkInfo(networkInfo2g);
setNetworkCountryIso(FAST_COUNTRY_ISO);
ExperimentalBandwidthMeter bandwidthMeterFast =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimateFast = bandwidthMeterFast.getBitrateEstimate();
setNetworkCountryIso(SLOW_COUNTRY_ISO);
ExperimentalBandwidthMeter bandwidthMeterSlow =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow);
}
@Test
public void
defaultInitialBitrateEstimate_for3G_forFastCountry_isGreaterThanEstimateForSlowCountry() {
setActiveNetworkInfo(networkInfo3g);
setNetworkCountryIso(FAST_COUNTRY_ISO);
ExperimentalBandwidthMeter bandwidthMeterFast =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimateFast = bandwidthMeterFast.getBitrateEstimate();
setNetworkCountryIso(SLOW_COUNTRY_ISO);
ExperimentalBandwidthMeter bandwidthMeterSlow =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow);
}
@Test
public void
defaultInitialBitrateEstimate_for4g_forFastCountry_isGreaterThanEstimateForSlowCountry() {
setActiveNetworkInfo(networkInfo4g);
setNetworkCountryIso(FAST_COUNTRY_ISO);
ExperimentalBandwidthMeter bandwidthMeterFast =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimateFast = bandwidthMeterFast.getBitrateEstimate();
setNetworkCountryIso(SLOW_COUNTRY_ISO);
ExperimentalBandwidthMeter bandwidthMeterSlow =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
assertThat(initialEstimateFast).isGreaterThan(initialEstimateSlow);
}
@Test
public void initialBitrateEstimateOverwrite_whileConnectedToNetwork_setsInitialEstimate() {
setActiveNetworkInfo(networkInfoWifi);
ExperimentalBandwidthMeter bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
.setInitialBitrateEstimate(123456789)
.build();
long initialEstimate = bandwidthMeter.getBitrateEstimate();
assertThat(initialEstimate).isEqualTo(123456789);
}
@Test
public void initialBitrateEstimateOverwrite_whileOffline_setsInitialEstimate() {
setActiveNetworkInfo(networkInfoOffline);
ExperimentalBandwidthMeter bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
.setInitialBitrateEstimate(123456789)
.build();
long initialEstimate = bandwidthMeter.getBitrateEstimate();
assertThat(initialEstimate).isEqualTo(123456789);
}
@Test
public void initialBitrateEstimateOverwrite_forWifi_whileConnectedToWifi_setsInitialEstimate() {
setActiveNetworkInfo(networkInfoWifi);
ExperimentalBandwidthMeter bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
.setInitialBitrateEstimate(C.NETWORK_TYPE_WIFI, 123456789)
.build();
long initialEstimate = bandwidthMeter.getBitrateEstimate();
assertThat(initialEstimate).isEqualTo(123456789);
}
@Test
public void
initialBitrateEstimateOverwrite_forWifi_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() {
setActiveNetworkInfo(networkInfo2g);
ExperimentalBandwidthMeter bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
.setInitialBitrateEstimate(C.NETWORK_TYPE_WIFI, 123456789)
.build();
long initialEstimate = bandwidthMeter.getBitrateEstimate();
assertThat(initialEstimate).isNotEqualTo(123456789);
}
@Test
public void
initialBitrateEstimateOverwrite_forEthernet_whileConnectedToEthernet_setsInitialEstimate() {
setActiveNetworkInfo(networkInfoEthernet);
ExperimentalBandwidthMeter bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
.setInitialBitrateEstimate(C.NETWORK_TYPE_ETHERNET, 123456789)
.build();
long initialEstimate = bandwidthMeter.getBitrateEstimate();
assertThat(initialEstimate).isEqualTo(123456789);
}
@Test
public void
initialBitrateEstimateOverwrite_forEthernet_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() {
setActiveNetworkInfo(networkInfo2g);
ExperimentalBandwidthMeter bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
.setInitialBitrateEstimate(C.NETWORK_TYPE_WIFI, 123456789)
.build();
long initialEstimate = bandwidthMeter.getBitrateEstimate();
assertThat(initialEstimate).isNotEqualTo(123456789);
}
@Test
public void initialBitrateEstimateOverwrite_for2G_whileConnectedTo2G_setsInitialEstimate() {
setActiveNetworkInfo(networkInfo2g);
ExperimentalBandwidthMeter bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
.setInitialBitrateEstimate(C.NETWORK_TYPE_2G, 123456789)
.build();
long initialEstimate = bandwidthMeter.getBitrateEstimate();
assertThat(initialEstimate).isEqualTo(123456789);
}
@Test
public void
initialBitrateEstimateOverwrite_for2G_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() {
setActiveNetworkInfo(networkInfoWifi);
ExperimentalBandwidthMeter bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
.setInitialBitrateEstimate(C.NETWORK_TYPE_2G, 123456789)
.build();
long initialEstimate = bandwidthMeter.getBitrateEstimate();
assertThat(initialEstimate).isNotEqualTo(123456789);
}
@Test
public void initialBitrateEstimateOverwrite_for3G_whileConnectedTo3G_setsInitialEstimate() {
setActiveNetworkInfo(networkInfo3g);
ExperimentalBandwidthMeter bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
.setInitialBitrateEstimate(C.NETWORK_TYPE_3G, 123456789)
.build();
long initialEstimate = bandwidthMeter.getBitrateEstimate();
assertThat(initialEstimate).isEqualTo(123456789);
}
@Test
public void
initialBitrateEstimateOverwrite_for3G_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() {
setActiveNetworkInfo(networkInfoWifi);
ExperimentalBandwidthMeter bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
.setInitialBitrateEstimate(C.NETWORK_TYPE_3G, 123456789)
.build();
long initialEstimate = bandwidthMeter.getBitrateEstimate();
assertThat(initialEstimate).isNotEqualTo(123456789);
}
@Test
public void initialBitrateEstimateOverwrite_for4G_whileConnectedTo4G_setsInitialEstimate() {
setActiveNetworkInfo(networkInfo4g);
ExperimentalBandwidthMeter bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
.setInitialBitrateEstimate(C.NETWORK_TYPE_4G, 123456789)
.build();
long initialEstimate = bandwidthMeter.getBitrateEstimate();
assertThat(initialEstimate).isEqualTo(123456789);
}
@Test
public void
initialBitrateEstimateOverwrite_for4G_whileConnectedToOtherNetwork_doesNotSetInitialEstimate() {
setActiveNetworkInfo(networkInfoWifi);
ExperimentalBandwidthMeter bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
.setInitialBitrateEstimate(C.NETWORK_TYPE_4G, 123456789)
.build();
long initialEstimate = bandwidthMeter.getBitrateEstimate();
assertThat(initialEstimate).isNotEqualTo(123456789);
}
@Test
public void initialBitrateEstimateOverwrite_forOffline_whileOffline_setsInitialEstimate() {
setActiveNetworkInfo(networkInfoOffline);
ExperimentalBandwidthMeter bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
.setInitialBitrateEstimate(C.NETWORK_TYPE_OFFLINE, 123456789)
.build();
long initialEstimate = bandwidthMeter.getBitrateEstimate();
assertThat(initialEstimate).isEqualTo(123456789);
}
@Test
public void
initialBitrateEstimateOverwrite_forOffline_whileConnectedToNetwork_doesNotSetInitialEstimate() {
setActiveNetworkInfo(networkInfoWifi);
ExperimentalBandwidthMeter bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
.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);
ExperimentalBandwidthMeter bandwidthMeterSlow =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimateSlow = bandwidthMeterSlow.getBitrateEstimate();
setNetworkCountryIso(FAST_COUNTRY_ISO);
ExperimentalBandwidthMeter bandwidthMeterFastWithSlowOverwrite =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
.setInitialBitrateEstimate(SLOW_COUNTRY_ISO)
.build();
long initialEstimateFastWithSlowOverwrite =
bandwidthMeterFastWithSlowOverwrite.getBitrateEstimate();
assertThat(initialEstimateFastWithSlowOverwrite).isEqualTo(initialEstimateSlow);
}
@Test
public void networkTypeOverride_updatesBitrateEstimate() {
setActiveNetworkInfo(networkInfoEthernet);
ExperimentalBandwidthMeter bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext()).build();
long initialEstimateEthernet = bandwidthMeter.getBitrateEstimate();
bandwidthMeter.setNetworkTypeOverride(C.NETWORK_TYPE_2G);
long initialEstimate2g = bandwidthMeter.getBitrateEstimate();
assertThat(initialEstimateEthernet).isGreaterThan(initialEstimate2g);
}
@Test
public void networkTypeOverride_doesFullReset() {
// Simulate transfers for an ethernet connection.
setActiveNetworkInfo(networkInfoEthernet);
FakeClock clock = new FakeClock(/* initialTimeMs= */ 0);
ExperimentalBandwidthMeter bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
.setClock(clock)
.build();
long[] bitrateEstimatesWithNewInstance = simulateTransfers(bandwidthMeter, clock);
// Create a new instance and seed with some transfers.
setActiveNetworkInfo(networkInfo2g);
bandwidthMeter =
new ExperimentalBandwidthMeter.Builder(ApplicationProvider.getApplicationContext())
.setClock(clock)
.build();
simulateTransfers(bandwidthMeter, clock);
// Override the network type to ethernet and simulate transfers again.
bandwidthMeter.setNetworkTypeOverride(C.NETWORK_TYPE_ETHERNET);
long[] bitrateEstimatesAfterReset = simulateTransfers(bandwidthMeter, clock);
// If overriding the network type fully reset the bandwidth meter, we expect the bitrate
// estimates generated during simulation to be the same.
assertThat(bitrateEstimatesAfterReset).isEqualTo(bitrateEstimatesWithNewInstance);
}
@Test
public void defaultInitialBitrateEstimate_withoutContext_isReasonable() {
ExperimentalBandwidthMeter bandwidthMeterWithBuilder =
new ExperimentalBandwidthMeter.Builder(/* context= */ null).build();
long initialEstimateWithBuilder = bandwidthMeterWithBuilder.getBitrateEstimate();
assertThat(initialEstimateWithBuilder).isGreaterThan(100_000L);
assertThat(initialEstimateWithBuilder).isLessThan(50_000_000L);
}
private void setActiveNetworkInfo(NetworkInfo networkInfo) {
Shadows.shadowOf(connectivityManager).setActiveNetworkInfo(networkInfo);
}
private void setNetworkCountryIso(String countryIso) {
Shadows.shadowOf(telephonyManager).setNetworkCountryIso(countryIso);
}
private static long[] simulateTransfers(
ExperimentalBandwidthMeter bandwidthMeter, FakeClock clock) {
long[] bitrateEstimates = new long[SIMULATED_TRANSFER_COUNT];
Random random = new Random(/* seed= */ 0);
DataSource dataSource = new FakeDataSource();
DataSpec dataSpec = new DataSpec(Uri.parse("https://test.com"));
for (int i = 0; i < SIMULATED_TRANSFER_COUNT; i++) {
bandwidthMeter.onTransferStart(dataSource, dataSpec, /* isNetwork= */ true);
clock.advanceTime(random.nextInt(/* bound= */ 5000));
bandwidthMeter.onBytesTransferred(
dataSource,
dataSpec,
/* isNetwork= */ true,
/* bytes= */ random.nextInt(5 * 1024 * 1024));
bandwidthMeter.onTransferEnd(dataSource, dataSpec, /* isNetwork= */ true);
bitrateEstimates[i] = bandwidthMeter.getBitrateEstimate();
}
return bitrateEstimates;
}
}

View file

@ -364,7 +364,6 @@ public final class CacheDataSourceTest {
new CacheWriter(
new CacheDataSource(cache, upstream2),
unboundedDataSpec,
/* allowShortContent= */ false,
/* temporaryBuffer= */ null,
/* progressListener= */ null);
cacheWriter.cache();
@ -414,7 +413,6 @@ public final class CacheDataSourceTest {
new CacheWriter(
new CacheDataSource(cache, upstream2),
unboundedDataSpec,
/* allowShortContent= */ false,
/* temporaryBuffer= */ null,
/* progressListener= */ null);
cacheWriter.cache();
@ -439,7 +437,6 @@ public final class CacheDataSourceTest {
new CacheWriter(
new CacheDataSource(cache, upstream),
dataSpec,
/* allowShortContent= */ false,
/* temporaryBuffer= */ null,
/* progressListener= */ null);
cacheWriter.cache();
@ -476,7 +473,6 @@ public final class CacheDataSourceTest {
new CacheWriter(
new CacheDataSource(cache, upstream),
dataSpec,
/* allowShortContent= */ false,
/* temporaryBuffer= */ null,
/* progressListener= */ null);
cacheWriter.cache();

View file

@ -30,7 +30,6 @@ import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.FileDataSource;
import com.google.android.exoplayer2.util.Util;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
@ -72,7 +71,6 @@ public final class CacheWriterTest {
new CacheWriter(
new CacheDataSource(cache, dataSource),
new DataSpec(Uri.parse("test_data")),
/* allowShortContent= */ false,
/* temporaryBuffer= */ null,
counters);
cacheWriter.cache();
@ -94,7 +92,6 @@ public final class CacheWriterTest {
new CacheWriter(
new CacheDataSource(cache, dataSource),
dataSpec,
/* allowShortContent= */ false,
/* temporaryBuffer= */ null,
counters);
cacheWriter.cache();
@ -106,7 +103,6 @@ public final class CacheWriterTest {
new CacheWriter(
new CacheDataSource(cache, dataSource),
new DataSpec(testUri),
/* allowShortContent= */ false,
/* temporaryBuffer= */ null,
counters);
cacheWriter.cache();
@ -129,7 +125,6 @@ public final class CacheWriterTest {
new CacheWriter(
new CacheDataSource(cache, dataSource),
dataSpec,
/* allowShortContent= */ false,
/* temporaryBuffer= */ null,
counters);
cacheWriter.cache();
@ -153,7 +148,6 @@ public final class CacheWriterTest {
new CacheWriter(
new CacheDataSource(cache, dataSource),
dataSpec,
/* allowShortContent= */ false,
/* temporaryBuffer= */ null,
counters);
cacheWriter.cache();
@ -165,7 +159,6 @@ public final class CacheWriterTest {
new CacheWriter(
new CacheDataSource(cache, dataSource),
new DataSpec(testUri),
/* allowShortContent= */ false,
/* temporaryBuffer= */ null,
counters);
cacheWriter.cache();
@ -187,7 +180,6 @@ public final class CacheWriterTest {
new CacheWriter(
new CacheDataSource(cache, dataSource),
dataSpec,
/* allowShortContent= */ true,
/* temporaryBuffer= */ null,
counters);
cacheWriter.cache();
@ -196,24 +188,6 @@ public final class CacheWriterTest {
assertCachedData(cache, fakeDataSet);
}
@Test
public void cacheThrowEOFException() throws Exception {
FakeDataSet fakeDataSet = new FakeDataSet().setRandomData("test_data", 100);
FakeDataSource dataSource = new FakeDataSource(fakeDataSet);
Uri testUri = Uri.parse("test_data");
DataSpec dataSpec = new DataSpec(testUri, /* position= */ 0, /* length= */ 1000);
CacheWriter cacheWriter =
new CacheWriter(
new CacheDataSource(cache, dataSource),
dataSpec,
/* allowShortContent= */ false,
/* temporaryBuffer= */ null,
/* progressListener= */ null);
assertThrows(EOFException.class, cacheWriter::cache);
}
@Test
public void cache_afterFailureOnClose_succeeds() throws Exception {
FakeDataSet fakeDataSet = new FakeDataSet().setRandomData("test_data", 100);
@ -237,7 +211,6 @@ public final class CacheWriterTest {
new CacheWriter(
cacheDataSource,
new DataSpec(Uri.parse("test_data")),
/* allowShortContent= */ false,
/* temporaryBuffer= */ null,
counters);
@ -276,7 +249,6 @@ public final class CacheWriterTest {
new CacheWriter(
new CacheDataSource(cache, dataSource),
new DataSpec(Uri.parse("test_data")),
/* allowShortContent= */ false,
/* temporaryBuffer= */ null,
counters);
cacheWriter.cache();

View file

@ -232,24 +232,27 @@ public abstract class DataSourceContractTest {
DataSpec dataSpec =
new DataSpec.Builder().setUri(resource.getUri()).setPosition(resourceLength).build();
try {
long length = dataSource.open(dataSpec);
// The DataSource.open() contract requires the returned length to equal the length in the
// DataSpec if set. This is true even though the DataSource implementation may know that
// fewer bytes will be read in this case.
if (length != C.LENGTH_UNSET) {
assertThat(length).isEqualTo(0);
}
try {
byte[] data =
unboundedReadsAreIndefinite() ? Util.EMPTY_BYTE_ARRAY : Util.readToEnd(dataSource);
assertThat(data).isEmpty();
long length = dataSource.open(dataSpec);
// The DataSource.open() contract requires the returned length to equal the length in the
// DataSpec if set. This is true even though the DataSource implementation may know that
// fewer bytes will be read in this case.
if (length != C.LENGTH_UNSET) {
assertThat(length).isEqualTo(0);
}
try {
byte[] data =
unboundedReadsAreIndefinite() ? Util.EMPTY_BYTE_ARRAY : Util.readToEnd(dataSource);
assertThat(data).isEmpty();
} catch (IOException e) {
// TODO: Remove this catch once the one below is removed.
throw new RuntimeException(e);
}
} catch (IOException e) {
// TODO: Remove this catch and require that implementations do not throw.
assertThat(DataSourceException.isCausedByPositionOutOfRange(e)).isTrue();
}
} catch (IOException e) {
// TODO: Remove this catch and require that implementations do not throw.
assertThat(DataSourceException.isCausedByPositionOutOfRange(e)).isTrue();
} finally {
dataSource.close();
}
@ -275,22 +278,25 @@ public abstract class DataSourceContractTest {
.setLength(1)
.build();
try {
long length = dataSource.open(dataSpec);
// The DataSource.open() contract requires the returned length to equal the length in the
// DataSpec if set. This is true even though the DataSource implementation may know that
// fewer bytes will be read in this case.
assertThat(length).isEqualTo(1);
try {
byte[] data =
unboundedReadsAreIndefinite() ? Util.EMPTY_BYTE_ARRAY : Util.readToEnd(dataSource);
assertThat(data).isEmpty();
long length = dataSource.open(dataSpec);
// The DataSource.open() contract requires the returned length to equal the length in the
// DataSpec if set. This is true even though the DataSource implementation may know that
// fewer bytes will be read in this case.
assertThat(length).isEqualTo(1);
try {
byte[] data =
unboundedReadsAreIndefinite() ? Util.EMPTY_BYTE_ARRAY : Util.readToEnd(dataSource);
assertThat(data).isEmpty();
} catch (IOException e) {
// TODO: Remove this catch once the one below is removed.
throw new RuntimeException(e);
}
} catch (IOException e) {
// TODO: Remove this catch and require that implementations do not throw.
assertThat(DataSourceException.isCausedByPositionOutOfRange(e)).isTrue();
}
} catch (IOException e) {
// TODO: Remove this catch and require that implementations do not throw.
assertThat(DataSourceException.isCausedByPositionOutOfRange(e)).isTrue();
} finally {
dataSource.close();
}