Make CronetDataSourceFactory an inner class of CronetDataSource

#exofixit

PiperOrigin-RevId: 348444280
This commit is contained in:
bachinger 2020-12-21 11:55:33 +00:00 committed by Oliver Woodman
parent df0b74e4c4
commit 62720858ed
6 changed files with 349 additions and 169 deletions

View File

@ -73,6 +73,8 @@
([#1807](https://github.com/google/ExoPlayer/issues/1807)).
* OkHttp extension:
* Add `OkHttpDataSource.Factory` and deprecate `OkHttpDataSourceFactory`.
* Cronet extension:
* Add `CronetDataSource.Factory` and deprecate `CronetDataSourceFactory`.
* Media2 extension
* Make media2-extension depend on AndroidX media2:media2-session:1.1.0 to
fix a deadlock while creating PlaybackStateCompat internally.

View File

@ -20,7 +20,7 @@ import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.database.DatabaseProvider;
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
import com.google.android.exoplayer2.ext.cronet.CronetDataSourceFactory;
import com.google.android.exoplayer2.ext.cronet.CronetDataSource;
import com.google.android.exoplayer2.ext.cronet.CronetEngineWrapper;
import com.google.android.exoplayer2.offline.ActionFileUpgradeUtil;
import com.google.android.exoplayer2.offline.DefaultDownloadIndex;
@ -81,7 +81,7 @@ public final class DemoUtil {
context = context.getApplicationContext();
CronetEngineWrapper cronetEngineWrapper = new CronetEngineWrapper(context);
httpDataSourceFactory =
new CronetDataSourceFactory(cronetEngineWrapper, Executors.newSingleThreadExecutor());
new CronetDataSource.Factory(cronetEngineWrapper, Executors.newSingleThreadExecutor());
}
return httpDataSourceFactory;
}

View File

@ -21,6 +21,7 @@ dependencies {
compileOnly 'org.jetbrains.kotlin:kotlin-annotations-jvm:' + kotlinAnnotationsVersion
testImplementation project(modulePrefix + 'library')
testImplementation project(modulePrefix + 'testutils')
testImplementation 'com.squareup.okhttp3:mockwebserver:' + mockWebServerVersion
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
}

View File

@ -25,9 +25,12 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.upstream.BaseDataSource;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSourceException;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.ConditionVariable;
@ -65,6 +68,186 @@ import org.chromium.net.UrlResponseInfo;
*/
public class CronetDataSource extends BaseDataSource implements HttpDataSource {
static {
ExoPlayerLibraryInfo.registerModule("goog.exo.cronet");
}
/** {@link DataSource.Factory} for {@link CronetDataSource} instances. */
public static final class Factory implements HttpDataSource.Factory {
private final CronetEngineWrapper cronetEngineWrapper;
private final Executor executor;
private final RequestProperties defaultRequestProperties;
private final DefaultHttpDataSource.Factory internalFallbackFactory;
@Nullable private HttpDataSource.Factory fallbackFactory;
@Nullable private Predicate<String> contentTypePredicate;
@Nullable private TransferListener transferListener;
private int connectTimeoutMs;
private int readTimeoutMs;
private boolean resetTimeoutOnRedirects;
private boolean handleSetCookieRequests;
/**
* Creates an instance.
*
* @param cronetEngineWrapper A {@link CronetEngineWrapper}.
* @param executor The {@link java.util.concurrent.Executor} that will handle responses. This
* may be a direct executor (i.e. executes tasks on the calling thread) in order to avoid a
* thread hop from Cronet's internal network thread to the response handling thread.
* However, to avoid slowing down overall network performance, care must be taken to make
* sure response handling is a fast operation when using a direct executor.
*/
public Factory(CronetEngineWrapper cronetEngineWrapper, Executor executor) {
this.cronetEngineWrapper = cronetEngineWrapper;
this.executor = executor;
defaultRequestProperties = new RequestProperties();
internalFallbackFactory = new DefaultHttpDataSource.Factory();
connectTimeoutMs = DEFAULT_CONNECT_TIMEOUT_MILLIS;
readTimeoutMs = DEFAULT_READ_TIMEOUT_MILLIS;
}
/** @deprecated Use {@link #setDefaultRequestProperties(Map)} instead. */
@Deprecated
@Override
public final RequestProperties getDefaultRequestProperties() {
return defaultRequestProperties;
}
@Override
public final Factory setDefaultRequestProperties(Map<String, String> defaultRequestProperties) {
this.defaultRequestProperties.clearAndSet(defaultRequestProperties);
internalFallbackFactory.setDefaultRequestProperties(defaultRequestProperties);
return this;
}
/**
* Sets the connect timeout, in milliseconds.
*
* <p>The default is {@link CronetDataSource#DEFAULT_CONNECT_TIMEOUT_MILLIS}.
*
* @param connectTimeoutMs The connect timeout, in milliseconds, that will be used.
* @return This factory.
*/
public Factory setConnectionTimeoutMs(int connectTimeoutMs) {
this.connectTimeoutMs = connectTimeoutMs;
internalFallbackFactory.setConnectTimeoutMs(connectTimeoutMs);
return this;
}
/**
* Sets whether the connect timeout is reset when a redirect occurs.
*
* <p>The default is {@code false}.
*
* @param resetTimeoutOnRedirects Whether the connect timeout is reset when a redirect occurs.
* @return This factory.
*/
public Factory setResetTimeoutOnRedirects(boolean resetTimeoutOnRedirects) {
this.resetTimeoutOnRedirects = resetTimeoutOnRedirects;
return this;
}
/**
* Sets whether "Set-Cookie" requests on redirect should be forwarded to the redirect url in the
* "Cookie" header.
*
* <p>The default is {@code false}.
*
* @param handleSetCookieRequests Whether "Set-Cookie" requests on redirect should be forwarded
* to the redirect url in the "Cookie" header.
* @return This factory.
*/
public Factory setHandleSetCookieRequests(boolean handleSetCookieRequests) {
this.handleSetCookieRequests = handleSetCookieRequests;
return this;
}
/**
* Sets the read timeout, in milliseconds.
*
* <p>The default is {@link CronetDataSource#DEFAULT_READ_TIMEOUT_MILLIS}.
*
* @param readTimeoutMs The connect timeout, in milliseconds, that will be used.
* @return This factory.
*/
public Factory setReadTimeoutMs(int readTimeoutMs) {
this.readTimeoutMs = readTimeoutMs;
internalFallbackFactory.setReadTimeoutMs(readTimeoutMs);
return this;
}
/**
* Sets a content type {@link Predicate}. If a content type is rejected by the predicate then a
* {@link HttpDataSource.InvalidContentTypeException} is thrown from {@link #open(DataSpec)}.
*
* <p>The default is {@code null}.
*
* @param contentTypePredicate The content type {@link Predicate}, or {@code null} to clear a
* predicate that was previously set.
* @return This factory.
*/
public Factory setContentTypePredicate(@Nullable Predicate<String> contentTypePredicate) {
this.contentTypePredicate = contentTypePredicate;
internalFallbackFactory.setContentTypePredicate(contentTypePredicate);
return this;
}
/**
* Sets the {@link TransferListener} that will be used.
*
* <p>The default is {@code null}.
*
* <p>See {@link DataSource#addTransferListener(TransferListener)}.
*
* @param transferListener The listener that will be used.
* @return This factory.
*/
public Factory setTransferListener(@Nullable TransferListener transferListener) {
this.transferListener = transferListener;
internalFallbackFactory.setTransferListener(transferListener);
return this;
}
/**
* Sets the fallback {@link HttpDataSource.Factory} that is used as a fallback if the {@link
* CronetEngineWrapper} fails to provide a {@link CronetEngine}.
*
* <p>By default a {@link DefaultHttpDataSource} is used as fallback factory.
*
* @param fallbackFactory The fallback factory that will be used.
* @return This factory.
*/
public Factory setFallbackFactory(@Nullable HttpDataSource.Factory fallbackFactory) {
this.fallbackFactory = fallbackFactory;
return this;
}
@Override
public HttpDataSource createDataSource() {
@Nullable CronetEngine cronetEngine = cronetEngineWrapper.getCronetEngine();
if (cronetEngine == null) {
return (fallbackFactory != null)
? fallbackFactory.createDataSource()
: internalFallbackFactory.createDataSource();
}
CronetDataSource dataSource =
new CronetDataSource(
cronetEngine,
executor,
connectTimeoutMs,
readTimeoutMs,
resetTimeoutOnRedirects,
handleSetCookieRequests,
defaultRequestProperties,
contentTypePredicate);
if (transferListener != null) {
dataSource.addTransferListener(transferListener);
}
return dataSource;
}
}
/**
* Thrown when an error is encountered when trying to open a {@link CronetDataSource}.
*/
@ -85,20 +268,11 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
super(errorMessage, dataSpec, TYPE_OPEN);
this.cronetConnectionStatus = cronetConnectionStatus;
}
}
static {
ExoPlayerLibraryInfo.registerModule("goog.exo.cronet");
}
/**
* The default connection timeout, in milliseconds.
*/
/** The default connection timeout, in milliseconds. */
public static final int DEFAULT_CONNECT_TIMEOUT_MILLIS = 8 * 1000;
/**
* The default read timeout, in milliseconds.
*/
/** The default read timeout, in milliseconds. */
public static final int DEFAULT_READ_TIMEOUT_MILLIS = 8 * 1000;
/* package */ final UrlRequest.Callback urlRequestCallback;
@ -149,16 +323,9 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
private volatile long currentConnectTimeoutMs;
/**
* Creates an instance.
*
* @param cronetEngine A CronetEngine.
* @param executor The {@link java.util.concurrent.Executor} that will handle responses. This may
* be a direct executor (i.e. executes tasks on the calling thread) in order to avoid a thread
* hop from Cronet's internal network thread to the response handling thread. However, to
* avoid slowing down overall network performance, care must be taken to make sure response
* handling is a fast operation when using a direct executor.
*/
/** @deprecated Use {@link CronetDataSource.Factory} instead. */
@SuppressWarnings("deprecation")
@Deprecated
public CronetDataSource(CronetEngine cronetEngine, Executor executor) {
this(
cronetEngine,
@ -169,21 +336,8 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
/* defaultRequestProperties= */ null);
}
/**
* Creates an instance.
*
* @param cronetEngine A CronetEngine.
* @param executor The {@link java.util.concurrent.Executor} that will handle responses. This may
* be a direct executor (i.e. executes tasks on the calling thread) in order to avoid a thread
* hop from Cronet's internal network thread to the response handling thread. However, to
* avoid slowing down overall network performance, care must be taken to make sure response
* handling is a fast operation when using a direct executor.
* @param connectTimeoutMs The connection timeout, in milliseconds.
* @param readTimeoutMs The read timeout, in milliseconds.
* @param resetTimeoutOnRedirects Whether the connect timeout is reset when a redirect occurs.
* @param defaultRequestProperties Optional default {@link RequestProperties} to be sent to the
* server as HTTP headers on every request.
*/
/** @deprecated Use {@link CronetDataSource.Factory} instead. */
@Deprecated
public CronetDataSource(
CronetEngine cronetEngine,
Executor executor,
@ -197,28 +351,13 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
connectTimeoutMs,
readTimeoutMs,
resetTimeoutOnRedirects,
Clock.DEFAULT,
/* handleSetCookieRequests= */ false,
defaultRequestProperties,
/* handleSetCookieRequests= */ false);
/* contentTypePredicate= */ null);
}
/**
* Creates an instance.
*
* @param cronetEngine A CronetEngine.
* @param executor The {@link java.util.concurrent.Executor} that will handle responses. This may
* be a direct executor (i.e. executes tasks on the calling thread) in order to avoid a thread
* hop from Cronet's internal network thread to the response handling thread. However, to
* avoid slowing down overall network performance, care must be taken to make sure response
* handling is a fast operation when using a direct executor.
* @param connectTimeoutMs The connection timeout, in milliseconds.
* @param readTimeoutMs The read timeout, in milliseconds.
* @param resetTimeoutOnRedirects Whether the connect timeout is reset when a redirect occurs.
* @param defaultRequestProperties Optional default {@link RequestProperties} to be sent to the
* server as HTTP headers on every request.
* @param handleSetCookieRequests Whether "Set-Cookie" requests on redirect should be forwarded to
* the redirect url in the "Cookie" header.
*/
/** @deprecated Use {@link CronetDataSource.Factory} instead. */
@Deprecated
public CronetDataSource(
CronetEngine cronetEngine,
Executor executor,
@ -233,26 +372,12 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
connectTimeoutMs,
readTimeoutMs,
resetTimeoutOnRedirects,
Clock.DEFAULT,
handleSetCookieRequests,
defaultRequestProperties,
handleSetCookieRequests);
/* contentTypePredicate= */ null);
}
/**
* Creates an instance.
*
* @param cronetEngine A CronetEngine.
* @param executor The {@link java.util.concurrent.Executor} that will handle responses. This may
* be a direct executor (i.e. executes tasks on the calling thread) in order to avoid a thread
* hop from Cronet's internal network thread to the response handling thread. However, to
* avoid slowing down overall network performance, care must be taken to make sure response
* handling is a fast operation when using a direct executor.
* @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the
* predicate then an {@link InvalidContentTypeException} is thrown from {@link
* #open(DataSpec)}.
* @deprecated Use {@link #CronetDataSource(CronetEngine, Executor)} and {@link
* #setContentTypePredicate(Predicate)}.
*/
/** @deprecated Use {@link CronetDataSource.Factory} instead. */
@SuppressWarnings("deprecation")
@Deprecated
public CronetDataSource(
@ -269,26 +394,7 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
/* defaultRequestProperties= */ null);
}
/**
* Creates an instance.
*
* @param cronetEngine A CronetEngine.
* @param executor The {@link java.util.concurrent.Executor} that will handle responses. This may
* be a direct executor (i.e. executes tasks on the calling thread) in order to avoid a thread
* hop from Cronet's internal network thread to the response handling thread. However, to
* avoid slowing down overall network performance, care must be taken to make sure response
* handling is a fast operation when using a direct executor.
* @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the
* predicate then an {@link InvalidContentTypeException} is thrown from {@link
* #open(DataSpec)}.
* @param connectTimeoutMs The connection timeout, in milliseconds.
* @param readTimeoutMs The read timeout, in milliseconds.
* @param resetTimeoutOnRedirects Whether the connect timeout is reset when a redirect occurs.
* @param defaultRequestProperties Optional default {@link RequestProperties} to be sent to the
* server as HTTP headers on every request.
* @deprecated Use {@link #CronetDataSource(CronetEngine, Executor, int, int, boolean,
* RequestProperties)} and {@link #setContentTypePredicate(Predicate)}.
*/
/** @deprecated Use {@link CronetDataSource.Factory} instead. */
@SuppressWarnings("deprecation")
@Deprecated
public CronetDataSource(
@ -310,28 +416,7 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
/* handleSetCookieRequests= */ false);
}
/**
* Creates an instance.
*
* @param cronetEngine A CronetEngine.
* @param executor The {@link java.util.concurrent.Executor} that will handle responses. This may
* be a direct executor (i.e. executes tasks on the calling thread) in order to avoid a thread
* hop from Cronet's internal network thread to the response handling thread. However, to
* avoid slowing down overall network performance, care must be taken to make sure response
* handling is a fast operation when using a direct executor.
* @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the
* predicate then an {@link InvalidContentTypeException} is thrown from {@link
* #open(DataSpec)}.
* @param connectTimeoutMs The connection timeout, in milliseconds.
* @param readTimeoutMs The read timeout, in milliseconds.
* @param resetTimeoutOnRedirects Whether the connect timeout is reset when a redirect occurs.
* @param defaultRequestProperties Optional default {@link RequestProperties} to be sent to the
* server as HTTP headers on every request.
* @param handleSetCookieRequests Whether "Set-Cookie" requests on redirect should be forwarded to
* the redirect url in the "Cookie" header.
* @deprecated Use {@link #CronetDataSource(CronetEngine, Executor, int, int, boolean,
* RequestProperties, boolean)} and {@link #setContentTypePredicate(Predicate)}.
*/
/** @deprecated Use {@link CronetDataSource.Factory} instead. */
@Deprecated
public CronetDataSource(
CronetEngine cronetEngine,
@ -348,31 +433,31 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
connectTimeoutMs,
readTimeoutMs,
resetTimeoutOnRedirects,
Clock.DEFAULT,
handleSetCookieRequests,
defaultRequestProperties,
handleSetCookieRequests);
this.contentTypePredicate = contentTypePredicate;
contentTypePredicate);
}
/* package */ CronetDataSource(
private CronetDataSource(
CronetEngine cronetEngine,
Executor executor,
int connectTimeoutMs,
int readTimeoutMs,
boolean resetTimeoutOnRedirects,
Clock clock,
boolean handleSetCookieRequests,
@Nullable RequestProperties defaultRequestProperties,
boolean handleSetCookieRequests) {
@Nullable Predicate<String> contentTypePredicate) {
super(/* isNetwork= */ true);
this.urlRequestCallback = new UrlRequestCallback();
this.cronetEngine = Assertions.checkNotNull(cronetEngine);
this.executor = Assertions.checkNotNull(executor);
this.connectTimeoutMs = connectTimeoutMs;
this.readTimeoutMs = readTimeoutMs;
this.resetTimeoutOnRedirects = resetTimeoutOnRedirects;
this.clock = Assertions.checkNotNull(clock);
this.defaultRequestProperties = defaultRequestProperties;
this.handleSetCookieRequests = handleSetCookieRequests;
this.contentTypePredicate = contentTypePredicate;
clock = Clock.DEFAULT;
urlRequestCallback = new UrlRequestCallback();
requestProperties = new RequestProperties();
operation = new ConditionVariable();
}
@ -384,6 +469,7 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
* @param contentTypePredicate The content type {@link Predicate}, or {@code null} to clear a
* predicate that was previously set.
*/
@Deprecated
public void setContentTypePredicate(@Nullable Predicate<String> contentTypePredicate) {
this.contentTypePredicate = contentTypePredicate;
}

View File

@ -21,14 +21,14 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.upstream.HttpDataSource.BaseFactory;
import com.google.android.exoplayer2.upstream.HttpDataSource.Factory;
import com.google.android.exoplayer2.upstream.TransferListener;
import java.util.concurrent.Executor;
import org.chromium.net.CronetEngine;
/**
* A {@link Factory} that produces {@link CronetDataSource}.
*/
/** @deprecated Use {@link CronetDataSource.Factory} instead. */
// Uses deprecated DefaultHttpDataSourceFactory
@SuppressWarnings("deprecation")
@Deprecated
public final class CronetDataSourceFactory extends BaseFactory {
/**

View File

@ -17,6 +17,7 @@ package com.google.android.exoplayer2.ext.cronet;
import static com.google.common.truth.Truth.assertThat;
import static java.lang.Math.min;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
@ -32,13 +33,15 @@ import static org.mockito.Mockito.when;
import android.net.Uri;
import android.os.ConditionVariable;
import android.os.SystemClock;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.upstream.HttpDataSource.HttpDataSourceException;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import java.io.InterruptedIOException;
@ -53,8 +56,12 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import okhttp3.Headers;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import org.chromium.net.CronetEngine;
import org.chromium.net.NetworkException;
import org.chromium.net.UrlRequest;
@ -100,21 +107,18 @@ public final class CronetDataSourceTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
HttpDataSource.RequestProperties defaultRequestProperties =
new HttpDataSource.RequestProperties();
defaultRequestProperties.set("defaultHeader1", "defaultValue1");
defaultRequestProperties.set("defaultHeader2", "defaultValue2");
Map<String, String> defaultRequestProperties = new HashMap<>();
defaultRequestProperties.put("defaultHeader1", "defaultValue1");
defaultRequestProperties.put("defaultHeader2", "defaultValue2");
dataSourceUnderTest =
new CronetDataSource(
mockCronetEngine,
mockExecutor,
TEST_CONNECT_TIMEOUT_MS,
TEST_READ_TIMEOUT_MS,
/* resetTimeoutOnRedirects= */ true,
Clock.DEFAULT,
defaultRequestProperties,
/* handleSetCookieRequests= */ false);
(CronetDataSource)
new CronetDataSource.Factory(new CronetEngineWrapper(mockCronetEngine), mockExecutor)
.setConnectionTimeoutMs(TEST_CONNECT_TIMEOUT_MS)
.setReadTimeoutMs(TEST_READ_TIMEOUT_MS)
.setResetTimeoutOnRedirects(true)
.setDefaultRequestProperties(defaultRequestProperties)
.createDataSource();
dataSourceUnderTest.addTransferListener(mockTransferListener);
when(mockCronetEngine.newUrlRequestBuilder(
anyString(), any(UrlRequest.Callback.class), any(Executor.class)))
@ -1134,15 +1138,13 @@ public final class CronetDataSourceTest {
testRedirectParseAndAttachCookie_dataSourceHandlesSetCookie_andPreservesOriginalRequestHeaders()
throws HttpDataSourceException {
dataSourceUnderTest =
new CronetDataSource(
mockCronetEngine,
mockExecutor,
TEST_CONNECT_TIMEOUT_MS,
TEST_READ_TIMEOUT_MS,
true, // resetTimeoutOnRedirects
Clock.DEFAULT,
null,
true);
(CronetDataSource)
new CronetDataSource.Factory(new CronetEngineWrapper(mockCronetEngine), mockExecutor)
.setConnectionTimeoutMs(TEST_CONNECT_TIMEOUT_MS)
.setReadTimeoutMs(TEST_READ_TIMEOUT_MS)
.setResetTimeoutOnRedirects(true)
.setHandleSetCookieRequests(true)
.createDataSource();
dataSourceUnderTest.addTransferListener(mockTransferListener);
dataSourceUnderTest.setRequestProperty("Content-Type", TEST_CONTENT_TYPE);
@ -1164,15 +1166,13 @@ public final class CronetDataSourceTest {
throws HttpDataSourceException {
testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000);
dataSourceUnderTest =
new CronetDataSource(
mockCronetEngine,
mockExecutor,
TEST_CONNECT_TIMEOUT_MS,
TEST_READ_TIMEOUT_MS,
/* resetTimeoutOnRedirects= */ true,
Clock.DEFAULT,
/* defaultRequestProperties= */ null,
/* handleSetCookieRequests= */ true);
(CronetDataSource)
new CronetDataSource.Factory(new CronetEngineWrapper(mockCronetEngine), mockExecutor)
.setConnectionTimeoutMs(TEST_CONNECT_TIMEOUT_MS)
.setReadTimeoutMs(TEST_READ_TIMEOUT_MS)
.setResetTimeoutOnRedirects(true)
.setHandleSetCookieRequests(true)
.createDataSource();
dataSourceUnderTest.addTransferListener(mockTransferListener);
dataSourceUnderTest.setRequestProperty("Content-Type", TEST_CONTENT_TYPE);
@ -1202,15 +1202,13 @@ public final class CronetDataSourceTest {
public void redirectNoSetCookieFollowsRedirect_dataSourceHandlesSetCookie()
throws HttpDataSourceException {
dataSourceUnderTest =
new CronetDataSource(
mockCronetEngine,
mockExecutor,
TEST_CONNECT_TIMEOUT_MS,
TEST_READ_TIMEOUT_MS,
/* resetTimeoutOnRedirects= */ true,
Clock.DEFAULT,
/* defaultRequestProperties= */ null,
/* handleSetCookieRequests= */ true);
(CronetDataSource)
new CronetDataSource.Factory(new CronetEngineWrapper(mockCronetEngine), mockExecutor)
.setConnectionTimeoutMs(TEST_CONNECT_TIMEOUT_MS)
.setReadTimeoutMs(TEST_READ_TIMEOUT_MS)
.setResetTimeoutOnRedirects(true)
.setHandleSetCookieRequests(true)
.createDataSource();
dataSourceUnderTest.addTransferListener(mockTransferListener);
mockSingleRedirectSuccess();
mockFollowRedirectSuccess();
@ -1356,6 +1354,99 @@ public final class CronetDataSourceTest {
verify(mockUrlRequestBuilder).allowDirectExecutor();
}
@Test
public void factorySetFallbackHttpDataSourceFactory_cronetNotAvailable_usesFallbackFactory()
throws HttpDataSourceException, InterruptedException {
MockWebServer mockWebServer = new MockWebServer();
mockWebServer.enqueue(new MockResponse());
CronetEngineWrapper cronetEngineWrapper = new CronetEngineWrapper((CronetEngine) null);
DefaultHttpDataSource.Factory fallbackFactory =
new DefaultHttpDataSource.Factory().setUserAgent("customFallbackFactoryUserAgent");
HttpDataSource dataSourceUnderTest =
new CronetDataSource.Factory(cronetEngineWrapper, Executors.newSingleThreadExecutor())
.setFallbackFactory(fallbackFactory)
.createDataSource();
dataSourceUnderTest.open(
new DataSpec.Builder().setUri(mockWebServer.url("/test-path").toString()).build());
Headers headers = mockWebServer.takeRequest(10, SECONDS).getHeaders();
assertThat(headers.get("user-agent")).isEqualTo("customFallbackFactoryUserAgent");
}
@Test
public void
factory_noFallbackFactoryCronetNotAvailable_delegateTransferListenerToInternalFallbackFactory()
throws HttpDataSourceException, InterruptedException {
MockWebServer mockWebServer = new MockWebServer();
mockWebServer.enqueue(new MockResponse());
CronetEngineWrapper cronetEngineWrapper = new CronetEngineWrapper((CronetEngine) null);
HttpDataSource dataSourceUnderTest =
new CronetDataSource.Factory(cronetEngineWrapper, Executors.newSingleThreadExecutor())
.setTransferListener(mockTransferListener)
.createDataSource();
DataSpec dataSpec =
new DataSpec.Builder().setUri(mockWebServer.url("/test-path").toString()).build();
dataSourceUnderTest.open(dataSpec);
Headers headers = mockWebServer.takeRequest(10, SECONDS).getHeaders();
assertThat(headers.get("user-agent")).isEqualTo(ExoPlayerLibraryInfo.DEFAULT_USER_AGENT);
verify(mockTransferListener)
.onTransferInitializing(eq(dataSourceUnderTest), eq(dataSpec), /* isNetwork= */ eq(true));
verify(mockTransferListener)
.onTransferStart(eq(dataSourceUnderTest), eq(dataSpec), /* isNetwork= */ eq(true));
}
@Test
public void
factory_noFallbackFactoryCronetNotAvailable_delegateDefaultRequestPropertiesToInternalFallbackFactory()
throws HttpDataSourceException, InterruptedException {
MockWebServer mockWebServer = new MockWebServer();
mockWebServer.enqueue(new MockResponse());
CronetEngineWrapper cronetEngineWrapper =
new CronetEngineWrapper(ApplicationProvider.getApplicationContext());
Map<String, String> defaultRequestProperties = new HashMap<>();
defaultRequestProperties.put("0", "defaultRequestProperty0");
HttpDataSource dataSourceUnderTest =
new CronetDataSource.Factory(cronetEngineWrapper, Executors.newSingleThreadExecutor())
.setDefaultRequestProperties(defaultRequestProperties)
.createDataSource();
dataSourceUnderTest.open(
new DataSpec.Builder().setUri(mockWebServer.url("/test-path").toString()).build());
Headers headers = mockWebServer.takeRequest(10, SECONDS).getHeaders();
assertThat(headers.get("0")).isEqualTo("defaultRequestProperty0");
assertThat(dataSourceUnderTest).isInstanceOf(DefaultHttpDataSource.class);
}
@Test
public void
factory_noFallbackFactoryCronetNotAvailable_delegateDefaultRequestPropertiesToInternalFallbackFactoryAfterCreation()
throws HttpDataSourceException, InterruptedException {
MockWebServer mockWebServer = new MockWebServer();
mockWebServer.enqueue(new MockResponse());
CronetEngineWrapper cronetEngineWrapper = new CronetEngineWrapper((CronetEngine) null);
Map<String, String> defaultRequestProperties = new HashMap<>();
defaultRequestProperties.put("0", "defaultRequestProperty0");
CronetDataSource.Factory factory =
new CronetDataSource.Factory(cronetEngineWrapper, Executors.newSingleThreadExecutor());
HttpDataSource dataSourceUnderTest =
factory.setDefaultRequestProperties(defaultRequestProperties).createDataSource();
defaultRequestProperties.clear();
defaultRequestProperties.put("1", "defaultRequestPropertyAfterCreation");
factory.setDefaultRequestProperties(defaultRequestProperties);
dataSourceUnderTest.open(
new DataSpec.Builder().setUri(mockWebServer.url("/test-path").toString()).build());
Headers headers = mockWebServer.takeRequest(10, SECONDS).getHeaders();
assertThat(headers.get("0")).isNull();
assertThat(headers.get("1")).isEqualTo("defaultRequestPropertyAfterCreation");
assertThat(dataSourceUnderTest).isInstanceOf(DefaultHttpDataSource.class);
}
// Helper methods.
private void mockStatusResponse() {