Commit 6114c894 by bachinger Committed by Christos Tsilopoulos

Make OkHttpDataSourceFactory an inner class of OkHttpDataSource

#exofixit

PiperOrigin-RevId: 347389531
parent e18892cd
...@@ -62,10 +62,16 @@ ...@@ -62,10 +62,16 @@
* Text: * Text:
* Gracefully handle null-terminated subtitle content in Matroska * Gracefully handle null-terminated subtitle content in Matroska
containers. containers.
* OkHttp extension:
* Add `OkHttpDataSource.Factory` and deprecate `OkHttpDataSourceFactory`.
* Media2 extension * Media2 extension
* Make media2-extension depend on AndroidX media2:media2-session:1.1.0 to * Make media2-extension depend on AndroidX media2:media2-session:1.1.0 to
fix a deadlock while creating PlaybackStateCompat internally. fix a deadlock while creating PlaybackStateCompat internally.
([#8011](https://github.com/google/ExoPlayer/issues/8011)). ([#8011](https://github.com/google/ExoPlayer/issues/8011)).
* MediaSession extension:
* Support `setPlaybackSpeed(float)` and disable it by default. Use
`MediaSessionConnector.setEnabledPlaybackActions(long)` to enable
([#8229](https://github.com/google/ExoPlayer/issues/8229)).
### 2.12.2 (2020-12-01) ### ### 2.12.2 (2020-12-01) ###
...@@ -128,10 +134,6 @@ ...@@ -128,10 +134,6 @@
`STATE_IDLE` or `STATE_ENDED`. `STATE_IDLE` or `STATE_ENDED`.
* Allow to remove all playlist items that makes the player reset. * Allow to remove all playlist items that makes the player reset.
([#8047](https://github.com/google/ExoPlayer/issues/8047)). ([#8047](https://github.com/google/ExoPlayer/issues/8047)).
* MediaSession extension:
* Support `setPlaybackSpeed(float)` and disable it by default. Use
`MediaSessionConnector.setEnabledPlaybackActions(long)` to enable
([#8229](https://github.com/google/ExoPlayer/issues/8229)).
### 2.12.1 (2020-10-23) ### ### 2.12.1 (2020-10-23) ###
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.ext.okhttp; package com.google.android.exoplayer2.ext.okhttp;
import static com.google.android.exoplayer2.ExoPlayerLibraryInfo.DEFAULT_USER_AGENT;
import static com.google.android.exoplayer2.util.Util.castNonNull; import static com.google.android.exoplayer2.util.Util.castNonNull;
import static java.lang.Math.min; import static java.lang.Math.min;
...@@ -23,9 +24,11 @@ import androidx.annotation.Nullable; ...@@ -23,9 +24,11 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.upstream.BaseDataSource; 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.DataSourceException;
import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.HttpDataSource; 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.Assertions;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
...@@ -41,6 +44,7 @@ import okhttp3.CacheControl; ...@@ -41,6 +44,7 @@ import okhttp3.CacheControl;
import okhttp3.Call; import okhttp3.Call;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
import okhttp3.MediaType; import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.RequestBody; import okhttp3.RequestBody;
import okhttp3.Response; import okhttp3.Response;
...@@ -59,6 +63,111 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource { ...@@ -59,6 +63,111 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
ExoPlayerLibraryInfo.registerModule("goog.exo.okhttp"); ExoPlayerLibraryInfo.registerModule("goog.exo.okhttp");
} }
/** {@link DataSource.Factory} for {@link OkHttpDataSource} instances. */
public static final class Factory implements HttpDataSource.Factory {
private final RequestProperties defaultRequestProperties;
private final Call.Factory callFactory;
@Nullable private String userAgent;
@Nullable private TransferListener transferListener;
@Nullable private CacheControl cacheControl;
@Nullable private Predicate<String> contentTypePredicate;
/**
* Creates an instance.
*
* @param callFactory A {@link Call.Factory} (typically an {@link OkHttpClient}) for use by the
* sources created by the factory.
*/
public Factory(Call.Factory callFactory) {
this.callFactory = callFactory;
defaultRequestProperties = new RequestProperties();
userAgent = DEFAULT_USER_AGENT;
}
/** @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);
return this;
}
/**
* Sets the user agent that will be used.
*
* <p>The default is {@link ExoPlayerLibraryInfo#DEFAULT_USER_AGENT}.
*
* @param userAgent The user agent that will be used.
* @return This factory.
*/
public Factory setUserAgent(String userAgent) {
this.userAgent = userAgent;
return this;
}
/**
* Sets the {@link CacheControl} that will be used.
*
* <p>The default is {@code null}.
*
* @param cacheControl The cache control that will be used.
* @return This factory.
*/
public Factory setCacheControl(@Nullable CacheControl cacheControl) {
this.cacheControl = cacheControl;
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
* OkHttpDataSource#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;
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;
return this;
}
@Override
public OkHttpDataSource createDataSource() {
OkHttpDataSource dataSource =
new OkHttpDataSource(
callFactory, userAgent, cacheControl, defaultRequestProperties, contentTypePredicate);
if (transferListener != null) {
dataSource.addTransferListener(transferListener);
}
return dataSource;
}
}
private static final byte[] SKIP_BUFFER = new byte[4096]; private static final byte[] SKIP_BUFFER = new byte[4096];
private final Call.Factory callFactory; private final Call.Factory callFactory;
...@@ -80,114 +189,54 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource { ...@@ -80,114 +189,54 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
private long bytesSkipped; private long bytesSkipped;
private long bytesRead; private long bytesRead;
/** /** @deprecated Use {@link OkHttpDataSource.Factory} instead. */
* Creates an instance. @SuppressWarnings("deprecation")
* @Deprecated
* @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use
* by the source.
*/
public OkHttpDataSource(Call.Factory callFactory) { public OkHttpDataSource(Call.Factory callFactory) {
this(callFactory, ExoPlayerLibraryInfo.DEFAULT_USER_AGENT); this(callFactory, DEFAULT_USER_AGENT);
} }
/** /** @deprecated Use {@link OkHttpDataSource.Factory} instead. */
* Creates an instance. @SuppressWarnings("deprecation")
* @Deprecated
* @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use
* by the source.
* @param userAgent An optional User-Agent string.
*/
public OkHttpDataSource(Call.Factory callFactory, @Nullable String userAgent) { public OkHttpDataSource(Call.Factory callFactory, @Nullable String userAgent) {
this(callFactory, userAgent, /* cacheControl= */ null, /* defaultRequestProperties= */ null); this(callFactory, userAgent, /* cacheControl= */ null, /* defaultRequestProperties= */ null);
} }
/** /** @deprecated Use {@link OkHttpDataSource.Factory} instead. */
* Creates an instance. @Deprecated
*
* @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use
* by the source.
* @param userAgent An optional User-Agent string.
* @param cacheControl An optional {@link CacheControl} for setting the Cache-Control header.
* @param defaultRequestProperties Optional default {@link RequestProperties} to be sent to the
* server as HTTP headers on every request.
*/
public OkHttpDataSource( public OkHttpDataSource(
Call.Factory callFactory, Call.Factory callFactory,
@Nullable String userAgent, @Nullable String userAgent,
@Nullable CacheControl cacheControl, @Nullable CacheControl cacheControl,
@Nullable RequestProperties defaultRequestProperties) { @Nullable RequestProperties defaultRequestProperties) {
super(/* isNetwork= */ true);
this.callFactory = Assertions.checkNotNull(callFactory);
this.userAgent = userAgent;
this.cacheControl = cacheControl;
this.defaultRequestProperties = defaultRequestProperties;
this.requestProperties = new RequestProperties();
}
/**
* Creates an instance.
*
* @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use
* by the source.
* @param userAgent An optional User-Agent string.
* @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the
* predicate then a {@link InvalidContentTypeException} is thrown from {@link
* #open(DataSpec)}.
* @deprecated Use {@link #OkHttpDataSource(Call.Factory, String)} and {@link
* #setContentTypePredicate(Predicate)}.
*/
@SuppressWarnings("deprecation")
@Deprecated
public OkHttpDataSource(
Call.Factory callFactory,
@Nullable String userAgent,
@Nullable Predicate<String> contentTypePredicate) {
this( this(
callFactory, callFactory,
userAgent, userAgent,
contentTypePredicate, cacheControl,
/* cacheControl= */ null, defaultRequestProperties,
/* defaultRequestProperties= */ null); /* contentTypePredicate= */ null);
} }
/** private OkHttpDataSource(
* Creates an instance.
*
* @param callFactory A {@link Call.Factory} (typically an {@link okhttp3.OkHttpClient}) for use
* by the source.
* @param userAgent An optional User-Agent string.
* @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the
* predicate then a {@link InvalidContentTypeException} is thrown from {@link
* #open(DataSpec)}.
* @param cacheControl An optional {@link CacheControl} for setting the Cache-Control header.
* @param defaultRequestProperties Optional default {@link RequestProperties} to be sent to the
* server as HTTP headers on every request.
* @deprecated Use {@link #OkHttpDataSource(Call.Factory, String, CacheControl,
* RequestProperties)} and {@link #setContentTypePredicate(Predicate)}.
*/
@Deprecated
public OkHttpDataSource(
Call.Factory callFactory, Call.Factory callFactory,
@Nullable String userAgent, @Nullable String userAgent,
@Nullable Predicate<String> contentTypePredicate,
@Nullable CacheControl cacheControl, @Nullable CacheControl cacheControl,
@Nullable RequestProperties defaultRequestProperties) { @Nullable RequestProperties defaultRequestProperties,
@Nullable Predicate<String> contentTypePredicate) {
super(/* isNetwork= */ true); super(/* isNetwork= */ true);
this.callFactory = Assertions.checkNotNull(callFactory); this.callFactory = Assertions.checkNotNull(callFactory);
this.userAgent = userAgent; this.userAgent = userAgent;
this.contentTypePredicate = contentTypePredicate;
this.cacheControl = cacheControl; this.cacheControl = cacheControl;
this.defaultRequestProperties = defaultRequestProperties; this.defaultRequestProperties = defaultRequestProperties;
this.contentTypePredicate = contentTypePredicate;
this.requestProperties = new RequestProperties(); this.requestProperties = new RequestProperties();
} }
/** /**
* Sets a content type {@link Predicate}. If a content type is rejected by the predicate then a * @deprecated Use {@link OkHttpDataSource.Factory#setContentTypePredicate(Predicate)} instead.
* {@link HttpDataSource.InvalidContentTypeException} is thrown from {@link #open(DataSpec)}.
*
* @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) { public void setContentTypePredicate(@Nullable Predicate<String> contentTypePredicate) {
this.contentTypePredicate = contentTypePredicate; this.contentTypePredicate = contentTypePredicate;
} }
...@@ -274,7 +323,7 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource { ...@@ -274,7 +323,7 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
} }
// Check for a valid content type. // Check for a valid content type.
MediaType mediaType = responseBody.contentType(); @Nullable MediaType mediaType = responseBody.contentType();
String contentType = mediaType != null ? mediaType.toString() : ""; String contentType = mediaType != null ? mediaType.toString() : "";
if (contentTypePredicate != null && !contentTypePredicate.apply(contentType)) { if (contentTypePredicate != null && !contentTypePredicate.apply(contentType)) {
closeConnectionQuietly(); closeConnectionQuietly();
...@@ -357,7 +406,7 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource { ...@@ -357,7 +406,7 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
long position = dataSpec.position; long position = dataSpec.position;
long length = dataSpec.length; long length = dataSpec.length;
HttpUrl url = HttpUrl.parse(dataSpec.uri.toString()); @Nullable HttpUrl url = HttpUrl.parse(dataSpec.uri.toString());
if (url == null) { if (url == null) {
throw new HttpDataSourceException( throw new HttpDataSourceException(
"Malformed URL", dataSpec, HttpDataSourceException.TYPE_OPEN); "Malformed URL", dataSpec, HttpDataSourceException.TYPE_OPEN);
...@@ -394,7 +443,7 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource { ...@@ -394,7 +443,7 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource {
builder.addHeader("Accept-Encoding", "identity"); builder.addHeader("Accept-Encoding", "identity");
} }
RequestBody requestBody = null; @Nullable RequestBody requestBody = null;
if (dataSpec.httpBody != null) { if (dataSpec.httpBody != null) {
requestBody = RequestBody.create(null, dataSpec.httpBody); requestBody = RequestBody.create(null, dataSpec.httpBody);
} else if (dataSpec.httpMethod == DataSpec.HTTP_METHOD_POST) { } else if (dataSpec.httpMethod == DataSpec.HTTP_METHOD_POST) {
......
...@@ -20,14 +20,12 @@ import static com.google.android.exoplayer2.ExoPlayerLibraryInfo.DEFAULT_USER_AG ...@@ -20,14 +20,12 @@ import static com.google.android.exoplayer2.ExoPlayerLibraryInfo.DEFAULT_USER_AG
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.upstream.HttpDataSource.BaseFactory; import com.google.android.exoplayer2.upstream.HttpDataSource.BaseFactory;
import com.google.android.exoplayer2.upstream.HttpDataSource.Factory;
import com.google.android.exoplayer2.upstream.TransferListener; import com.google.android.exoplayer2.upstream.TransferListener;
import okhttp3.CacheControl; import okhttp3.CacheControl;
import okhttp3.Call; import okhttp3.Call;
/** /** @deprecated Use {@link OkHttpDataSource.Factory} instead. */
* A {@link Factory} that produces {@link OkHttpDataSource}. @Deprecated
*/
public final class OkHttpDataSourceFactory extends BaseFactory { public final class OkHttpDataSourceFactory extends BaseFactory {
private final Call.Factory callFactory; private final Call.Factory callFactory;
...@@ -102,6 +100,8 @@ public final class OkHttpDataSourceFactory extends BaseFactory { ...@@ -102,6 +100,8 @@ public final class OkHttpDataSourceFactory extends BaseFactory {
this.cacheControl = cacheControl; this.cacheControl = cacheControl;
} }
// Calls deprecated constructor.
@SuppressWarnings("deprecation")
@Override @Override
protected OkHttpDataSource createDataSourceInternal( protected OkHttpDataSource createDataSourceInternal(
HttpDataSource.RequestProperties defaultRequestProperties) { HttpDataSource.RequestProperties defaultRequestProperties) {
......
...@@ -59,15 +59,16 @@ public class OkHttpDataSourceTest { ...@@ -59,15 +59,16 @@ public class OkHttpDataSourceTest {
MockWebServer mockWebServer = new MockWebServer(); MockWebServer mockWebServer = new MockWebServer();
mockWebServer.enqueue(new MockResponse()); mockWebServer.enqueue(new MockResponse());
String propertyFromConstructor = "fromConstructor"; String propertyFromFactory = "fromFactory";
HttpDataSource.RequestProperties constructorProperties = new HttpDataSource.RequestProperties(); Map<String, String> defaultRequestProperties = new HashMap<>();
constructorProperties.set("0", propertyFromConstructor); defaultRequestProperties.put("0", propertyFromFactory);
constructorProperties.set("1", propertyFromConstructor); defaultRequestProperties.put("1", propertyFromFactory);
constructorProperties.set("2", propertyFromConstructor); defaultRequestProperties.put("2", propertyFromFactory);
constructorProperties.set("4", propertyFromConstructor); defaultRequestProperties.put("4", propertyFromFactory);
OkHttpDataSource dataSource = HttpDataSource dataSource =
new OkHttpDataSource( new OkHttpDataSource.Factory(new OkHttpClient())
new OkHttpClient(), "testAgent", /* cacheControl= */ null, constructorProperties); .setDefaultRequestProperties(defaultRequestProperties)
.createDataSource();
String propertyFromSetter = "fromSetter"; String propertyFromSetter = "fromSetter";
dataSource.setRequestProperty("1", propertyFromSetter); dataSource.setRequestProperty("1", propertyFromSetter);
...@@ -91,7 +92,7 @@ public class OkHttpDataSourceTest { ...@@ -91,7 +92,7 @@ public class OkHttpDataSourceTest {
dataSource.open(dataSpec); dataSource.open(dataSpec);
Headers headers = mockWebServer.takeRequest(10, SECONDS).getHeaders(); Headers headers = mockWebServer.takeRequest(10, SECONDS).getHeaders();
assertThat(headers.get("0")).isEqualTo(propertyFromConstructor); assertThat(headers.get("0")).isEqualTo(propertyFromFactory);
assertThat(headers.get("1")).isEqualTo(propertyFromSetter); assertThat(headers.get("1")).isEqualTo(propertyFromSetter);
assertThat(headers.get("2")).isEqualTo(propertyFromDataSpec); assertThat(headers.get("2")).isEqualTo(propertyFromDataSpec);
assertThat(headers.get("3")).isEqualTo(propertyFromDataSpec); assertThat(headers.get("3")).isEqualTo(propertyFromDataSpec);
...@@ -101,16 +102,13 @@ public class OkHttpDataSourceTest { ...@@ -101,16 +102,13 @@ public class OkHttpDataSourceTest {
} }
@Test @Test
public void open_invalidResponseCode() throws Exception { public void open_invalidResponseCode() {
MockWebServer mockWebServer = new MockWebServer(); MockWebServer mockWebServer = new MockWebServer();
mockWebServer.enqueue(new MockResponse().setResponseCode(404).setBody("failure msg")); mockWebServer.enqueue(new MockResponse().setResponseCode(404).setBody("failure msg"));
OkHttpDataSource okHttpDataSource = HttpDataSource okHttpDataSource =
new OkHttpDataSource( new OkHttpDataSource.Factory(new OkHttpClient()).createDataSource();
new OkHttpClient(),
"testAgent",
/* cacheControl= */ null,
/* defaultRequestProperties= */ null);
DataSpec dataSpec = DataSpec dataSpec =
new DataSpec.Builder().setUri(mockWebServer.url("/test-path").toString()).build(); new DataSpec.Builder().setUri(mockWebServer.url("/test-path").toString()).build();
...@@ -122,4 +120,22 @@ public class OkHttpDataSourceTest { ...@@ -122,4 +120,22 @@ public class OkHttpDataSourceTest {
assertThat(exception.responseCode).isEqualTo(404); assertThat(exception.responseCode).isEqualTo(404);
assertThat(exception.responseBody).isEqualTo("failure msg".getBytes(Charsets.UTF_8)); assertThat(exception.responseBody).isEqualTo("failure msg".getBytes(Charsets.UTF_8));
} }
@Test
public void factory_setRequestPropertyAfterCreation_setsCorrectHeaders() throws Exception {
MockWebServer mockWebServer = new MockWebServer();
mockWebServer.enqueue(new MockResponse());
DataSpec dataSpec =
new DataSpec.Builder().setUri(mockWebServer.url("/test-path").toString()).build();
OkHttpDataSource.Factory factory = new OkHttpDataSource.Factory(new OkHttpClient());
OkHttpDataSource dataSource = factory.createDataSource();
Map<String, String> defaultRequestProperties = new HashMap<>();
defaultRequestProperties.put("0", "afterCreation");
factory.setDefaultRequestProperties(defaultRequestProperties);
dataSource.open(dataSpec);
Headers headers = mockWebServer.takeRequest(10, SECONDS).getHeaders();
assertThat(headers.get("0")).isEqualTo("afterCreation");
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment