diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 19751c4600..781a41be86 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -99,6 +99,8 @@ ([#1807](https://github.com/google/ExoPlayer/issues/1807)). * Metadata retriever: * Parse Google Photos HEIC motion photos metadata. +* Data sources: + * Use the user agent of the underlying network stack by default. * IMA extension: * Add support for playback of ads in playlists ([#3750](https://github.com/google/ExoPlayer/issues/3750)). @@ -116,6 +118,8 @@ * Add `OkHttpDataSource.Factory` and deprecate `OkHttpDataSourceFactory`. * Cronet extension: * Add `CronetDataSource.Factory` and deprecate `CronetDataSourceFactory`. + * Support setting the user agent on `CronetDataSource.Factory` and + `CronetEngineWrapper`. * Media2 extension * Make media2-extension depend on AndroidX media2:media2-session:1.1.0 to fix a deadlock while creating PlaybackStateCompat internally. diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DemoUtil.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/DemoUtil.java index 7774ee2bbe..704d819db4 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DemoUtil.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/DemoUtil.java @@ -16,7 +16,9 @@ package com.google.android.exoplayer2.demo; import android.content.Context; +import android.os.Build; import com.google.android.exoplayer2.DefaultRenderersFactory; +import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.RenderersFactory; import com.google.android.exoplayer2.database.DatabaseProvider; import com.google.android.exoplayer2.database.ExoDatabaseProvider; @@ -44,6 +46,13 @@ public final class DemoUtil { public static final String DOWNLOAD_NOTIFICATION_CHANNEL_ID = "download_channel"; + private static final String USER_AGENT = + "ExoPlayerDemo/" + + ExoPlayerLibraryInfo.VERSION + + " (Linux; Android " + + Build.VERSION.RELEASE + + ") " + + ExoPlayerLibraryInfo.VERSION_SLASHY; private static final String TAG = "DemoUtil"; private static final String DOWNLOAD_ACTION_FILE = "actions"; private static final String DOWNLOAD_TRACKER_ACTION_FILE = "tracked_actions"; @@ -79,7 +88,8 @@ public final class DemoUtil { public static synchronized HttpDataSource.Factory getHttpDataSourceFactory(Context context) { if (httpDataSourceFactory == null) { context = context.getApplicationContext(); - CronetEngineWrapper cronetEngineWrapper = new CronetEngineWrapper(context); + CronetEngineWrapper cronetEngineWrapper = + new CronetEngineWrapper(context, USER_AGENT, /* preferGMSCoreCronet= */ false); httpDataSourceFactory = new CronetDataSource.Factory(cronetEngineWrapper, Executors.newSingleThreadExecutor()); } diff --git a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java index bcaef38898..9798eea656 100644 --- a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java +++ b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java @@ -83,6 +83,7 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { @Nullable private HttpDataSource.Factory fallbackFactory; @Nullable private Predicate contentTypePredicate; @Nullable private TransferListener transferListener; + @Nullable private String userAgent; private int connectTimeoutMs; private int readTimeoutMs; private boolean resetTimeoutOnRedirects; @@ -121,6 +122,22 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { return this; } + /** + * Sets the user agent that will be used. + * + *

The default is {@code null}, which causes the default user agent of the underlying {@link + * CronetEngine} to be used. + * + * @param userAgent The user agent that will be used, or {@code null} to use the default user + * agent of the underlying {@link CronetEngine}. + * @return This factory. + */ + public Factory setUserAgent(@Nullable String userAgent) { + this.userAgent = userAgent; + internalFallbackFactory.setUserAgent(userAgent); + return this; + } + /** * Sets the connect timeout, in milliseconds. * @@ -239,6 +256,7 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { readTimeoutMs, resetTimeoutOnRedirects, handleSetCookieRequests, + userAgent, defaultRequestProperties, contentTypePredicate); if (transferListener != null) { @@ -293,6 +311,7 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { private final int readTimeoutMs; private final boolean resetTimeoutOnRedirects; private final boolean handleSetCookieRequests; + @Nullable private final String userAgent; @Nullable private final RequestProperties defaultRequestProperties; private final RequestProperties requestProperties; private final ConditionVariable operation; @@ -352,6 +371,7 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { readTimeoutMs, resetTimeoutOnRedirects, /* handleSetCookieRequests= */ false, + /* userAgent= */ null, defaultRequestProperties, /* contentTypePredicate= */ null); } @@ -373,6 +393,7 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { readTimeoutMs, resetTimeoutOnRedirects, handleSetCookieRequests, + /* userAgent= */ null, defaultRequestProperties, /* contentTypePredicate= */ null); } @@ -434,6 +455,7 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { readTimeoutMs, resetTimeoutOnRedirects, handleSetCookieRequests, + /* userAgent= */ null, defaultRequestProperties, contentTypePredicate); } @@ -445,6 +467,7 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { int readTimeoutMs, boolean resetTimeoutOnRedirects, boolean handleSetCookieRequests, + @Nullable String userAgent, @Nullable RequestProperties defaultRequestProperties, @Nullable Predicate contentTypePredicate) { super(/* isNetwork= */ true); @@ -453,8 +476,9 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { this.connectTimeoutMs = connectTimeoutMs; this.readTimeoutMs = readTimeoutMs; this.resetTimeoutOnRedirects = resetTimeoutOnRedirects; - this.defaultRequestProperties = defaultRequestProperties; this.handleSetCookieRequests = handleSetCookieRequests; + this.userAgent = userAgent; + this.defaultRequestProperties = defaultRequestProperties; this.contentTypePredicate = contentTypePredicate; clock = Clock.DEFAULT; urlRequestCallback = new UrlRequestCallback(); @@ -820,6 +844,9 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { } requestBuilder.addHeader("Range", rangeValue.toString()); } + if (userAgent != null) { + requestBuilder.addHeader("User-Agent", userAgent); + } // TODO: Uncomment when https://bugs.chromium.org/p/chromium/issues/detail?id=711810 is fixed // (adjusting the code as necessary). // Force identity encoding unless gzip is allowed. diff --git a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceFactory.java b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceFactory.java index 443d8049a4..f979e99b7d 100644 --- a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceFactory.java +++ b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceFactory.java @@ -15,7 +15,6 @@ */ package com.google.android.exoplayer2.ext.cronet; -import static com.google.android.exoplayer2.ExoPlayerLibraryInfo.DEFAULT_USER_AGENT; import androidx.annotation.Nullable; import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; @@ -92,7 +91,7 @@ public final class CronetDataSourceFactory extends BaseFactory { * @param executor The {@link java.util.concurrent.Executor} that will perform the requests. */ public CronetDataSourceFactory(CronetEngineWrapper cronetEngineWrapper, Executor executor) { - this(cronetEngineWrapper, executor, DEFAULT_USER_AGENT); + this(cronetEngineWrapper, executor, /* userAgent= */ (String) null); } /** @@ -106,10 +105,12 @@ public final class CronetDataSourceFactory extends BaseFactory { * * @param cronetEngineWrapper A {@link CronetEngineWrapper}. * @param executor The {@link java.util.concurrent.Executor} that will perform the requests. - * @param userAgent A user agent used to create a fallback HttpDataSource if needed. + * @param userAgent The user agent that will be used by the fallback {@link HttpDataSource} if + * needed, or {@code null} for the fallback to use the default user agent of the underlying + * platform. */ public CronetDataSourceFactory( - CronetEngineWrapper cronetEngineWrapper, Executor executor, String userAgent) { + CronetEngineWrapper cronetEngineWrapper, Executor executor, @Nullable String userAgent) { this( cronetEngineWrapper, executor, @@ -136,7 +137,9 @@ public final class CronetDataSourceFactory extends BaseFactory { * @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 userAgent A user agent used to create a fallback HttpDataSource if needed. + * @param userAgent The user agent that will be used by the fallback {@link HttpDataSource} if + * needed, or {@code null} for the fallback to use the default user agent of the underlying + * platform. */ public CronetDataSourceFactory( CronetEngineWrapper cronetEngineWrapper, @@ -144,7 +147,7 @@ public final class CronetDataSourceFactory extends BaseFactory { int connectTimeoutMs, int readTimeoutMs, boolean resetTimeoutOnRedirects, - String userAgent) { + @Nullable String userAgent) { this( cronetEngineWrapper, executor, @@ -238,7 +241,7 @@ public final class CronetDataSourceFactory extends BaseFactory { CronetEngineWrapper cronetEngineWrapper, Executor executor, @Nullable TransferListener transferListener) { - this(cronetEngineWrapper, executor, transferListener, DEFAULT_USER_AGENT); + this(cronetEngineWrapper, executor, transferListener, /* userAgent= */ (String) null); } /** @@ -253,13 +256,15 @@ public final class CronetDataSourceFactory extends BaseFactory { * @param cronetEngineWrapper A {@link CronetEngineWrapper}. * @param executor The {@link java.util.concurrent.Executor} that will perform the requests. * @param transferListener An optional listener. - * @param userAgent A user agent used to create a fallback HttpDataSource if needed. + * @param userAgent The user agent that will be used by the fallback {@link HttpDataSource} if + * needed, or {@code null} for the fallback to use the default user agent of the underlying + * platform. */ public CronetDataSourceFactory( CronetEngineWrapper cronetEngineWrapper, Executor executor, @Nullable TransferListener transferListener, - String userAgent) { + @Nullable String userAgent) { this( cronetEngineWrapper, executor, @@ -287,7 +292,9 @@ public final class CronetDataSourceFactory extends BaseFactory { * @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 userAgent A user agent used to create a fallback HttpDataSource if needed. + * @param userAgent The user agent that will be used by the fallback {@link HttpDataSource} if + * needed, or {@code null} for the fallback to use the default user agent of the underlying + * platform. */ public CronetDataSourceFactory( CronetEngineWrapper cronetEngineWrapper, @@ -296,7 +303,7 @@ public final class CronetDataSourceFactory extends BaseFactory { int connectTimeoutMs, int readTimeoutMs, boolean resetTimeoutOnRedirects, - String userAgent) { + @Nullable String userAgent) { this( cronetEngineWrapper, executor, diff --git a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineWrapper.java b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineWrapper.java index 9f709b14d0..d9332342e3 100644 --- a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineWrapper.java +++ b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetEngineWrapper.java @@ -73,25 +73,29 @@ public final class CronetEngineWrapper { public static final int SOURCE_UNAVAILABLE = 4; /** - * Creates a wrapper for a {@link CronetEngine} which automatically selects the most suitable - * {@link CronetProvider}. Sets wrapper to prefer natively bundled Cronet over GMSCore Cronet - * if both are available. + * Creates a wrapper for a {@link CronetEngine} built using the most suitable {@link + * CronetProvider}. When natively bundled Cronet and GMSCore Cronet are both available, the + * natively bundled provider is preferred. * * @param context A context. */ public CronetEngineWrapper(Context context) { - this(context, false); + this(context, /* userAgent= */ null, /* preferGMSCoreCronet= */ false); } /** - * Creates a wrapper for a {@link CronetEngine} which automatically selects the most suitable - * {@link CronetProvider} based on user preference. + * Creates a wrapper for a {@link CronetEngine} built using the most suitable {@link + * CronetProvider}. When natively bundled Cronet and GMSCore Cronet are both available, {@code + * preferGMSCoreCronet} determines which is preferred. * * @param context A context. + * @param userAgent A default user agent, or {@code null} to use a default user agent of the + * {@link CronetEngine}. * @param preferGMSCoreCronet Whether Cronet from GMSCore should be preferred over natively * bundled Cronet if both are available. */ - public CronetEngineWrapper(Context context, boolean preferGMSCoreCronet) { + public CronetEngineWrapper( + Context context, @Nullable String userAgent, boolean preferGMSCoreCronet) { CronetEngine cronetEngine = null; @CronetEngineSource int cronetEngineSource = SOURCE_UNAVAILABLE; List cronetProviders = new ArrayList<>(CronetProvider.getAllProviders(context)); @@ -108,7 +112,11 @@ public final class CronetEngineWrapper { for (int i = 0; i < cronetProviders.size() && cronetEngine == null; i++) { String providerName = cronetProviders.get(i).getName(); try { - cronetEngine = cronetProviders.get(i).createBuilder().build(); + CronetEngine.Builder cronetEngineBuilder = cronetProviders.get(i).createBuilder(); + if (userAgent != null) { + cronetEngineBuilder.setUserAgent(userAgent); + } + cronetEngine = cronetEngineBuilder.build(); if (providerComparator.isNativeProvider(providerName)) { cronetEngineSource = SOURCE_NATIVE; } else if (providerComparator.isGMSCoreProvider(providerName)) { @@ -133,9 +141,9 @@ public final class CronetEngineWrapper { } /** - * Creates a wrapper for an existing CronetEngine. + * Creates a wrapper for an existing {@link CronetEngine}. * - * @param cronetEngine An existing CronetEngine. + * @param cronetEngine The CronetEngine to wrap. */ public CronetEngineWrapper(CronetEngine cronetEngine) { this.cronetEngine = cronetEngine; diff --git a/extensions/cronet/src/test/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceTest.java b/extensions/cronet/src/test/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceTest.java index 9accd10228..631e1300d6 100644 --- a/extensions/cronet/src/test/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceTest.java +++ b/extensions/cronet/src/test/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceTest.java @@ -36,7 +36,6 @@ 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; @@ -1412,8 +1411,6 @@ public final class CronetDataSourceTest { 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) diff --git a/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java b/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java index fe551bb15c..d23dd22574 100644 --- a/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java +++ b/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSource.java @@ -15,7 +15,6 @@ */ 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 java.lang.Math.min; @@ -83,7 +82,6 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource { public Factory(Call.Factory callFactory) { this.callFactory = callFactory; defaultRequestProperties = new RequestProperties(); - userAgent = DEFAULT_USER_AGENT; } /** @deprecated Use {@link #setDefaultRequestProperties(Map)} instead. */ @@ -102,12 +100,14 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource { /** * Sets the user agent that will be used. * - *

The default is {@link ExoPlayerLibraryInfo#DEFAULT_USER_AGENT}. + *

The default is {@code null}, which causes the default user agent of the underlying {@link + * OkHttpClient} to be used. * - * @param userAgent The user agent that will be used. + * @param userAgent The user agent that will be used, or {@code null} to use the default user + * agent of the underlying {@link OkHttpClient}. * @return This factory. */ - public Factory setUserAgent(String userAgent) { + public Factory setUserAgent(@Nullable String userAgent) { this.userAgent = userAgent; return this; } @@ -193,7 +193,7 @@ public class OkHttpDataSource extends BaseDataSource implements HttpDataSource { @SuppressWarnings("deprecation") @Deprecated public OkHttpDataSource(Call.Factory callFactory) { - this(callFactory, DEFAULT_USER_AGENT); + this(callFactory, /* userAgent= */ null); } /** @deprecated Use {@link OkHttpDataSource.Factory} instead. */ diff --git a/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceFactory.java b/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceFactory.java index a8ef3a521e..08e337f52b 100644 --- a/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceFactory.java +++ b/extensions/okhttp/src/main/java/com/google/android/exoplayer2/ext/okhttp/OkHttpDataSourceFactory.java @@ -15,7 +15,6 @@ */ package com.google.android.exoplayer2.ext.okhttp; -import static com.google.android.exoplayer2.ExoPlayerLibraryInfo.DEFAULT_USER_AGENT; import androidx.annotation.Nullable; import com.google.android.exoplayer2.upstream.HttpDataSource; @@ -40,7 +39,7 @@ public final class OkHttpDataSourceFactory extends BaseFactory { * by the sources created by the factory. */ public OkHttpDataSourceFactory(Call.Factory callFactory) { - this(callFactory, DEFAULT_USER_AGENT, /* listener= */ null, /* cacheControl= */ null); + this(callFactory, /* userAgent= */ null, /* listener= */ null, /* cacheControl= */ null); } /** diff --git a/library/common/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java b/library/common/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java index 0caa3d50df..572099dfce 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java @@ -46,9 +46,14 @@ public final class ExoPlayerLibraryInfo { // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. public static final int VERSION_INT = 2012002; - /** The default user agent for requests made by the library. */ + /** + * The default user agent for requests made by the library. + * + * @deprecated ExoPlayer now uses the user agent of the underlying network stack by default. + */ + @Deprecated public static final String DEFAULT_USER_AGENT = - VERSION_SLASHY + " (Linux;Android " + Build.VERSION.RELEASE + ") " + VERSION_SLASHY; + VERSION_SLASHY + " (Linux; Android " + Build.VERSION.RELEASE + ") " + VERSION_SLASHY; /** * Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSourceDrmHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSourceDrmHelper.java index f4a7b89fc7..0529ec3127 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSourceDrmHelper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSourceDrmHelper.java @@ -15,7 +15,6 @@ */ package com.google.android.exoplayer2.source; -import static com.google.android.exoplayer2.ExoPlayerLibraryInfo.DEFAULT_USER_AGENT; import static com.google.android.exoplayer2.drm.DefaultDrmSessionManager.MODE_PLAYBACK; import androidx.annotation.Nullable; @@ -24,6 +23,7 @@ import com.google.android.exoplayer2.drm.DefaultDrmSessionManager; import com.google.android.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.FrameworkMediaDrm; import com.google.android.exoplayer2.drm.HttpMediaDrmCallback; +import com.google.android.exoplayer2.upstream.DefaultHttpDataSource; import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.util.Assertions; @@ -73,7 +73,7 @@ public final class MediaSourceDrmHelper { HttpDataSource.Factory dataSourceFactory = drmHttpDataSourceFactory != null ? drmHttpDataSourceFactory - : new DefaultHttpDataSourceFactory(userAgent != null ? userAgent : DEFAULT_USER_AGENT); + : new DefaultHttpDataSource.Factory().setUserAgent(userAgent); HttpMediaDrmCallback httpDrmCallback = new HttpMediaDrmCallback( drmConfiguration.licenseUri == null ? null : drmConfiguration.licenseUri.toString(), diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSource.java index 534378a635..cf89180b43 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSource.java @@ -19,7 +19,6 @@ import android.content.ContentResolver; import android.content.Context; import android.net.Uri; import androidx.annotation.Nullable; -import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Util; @@ -89,7 +88,7 @@ public final class DefaultDataSource implements DataSource { public DefaultDataSource(Context context, boolean allowCrossProtocolRedirects) { this( context, - ExoPlayerLibraryInfo.DEFAULT_USER_AGENT, + /* userAgent= */ null, DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS, DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, allowCrossProtocolRedirects); @@ -99,11 +98,13 @@ public final class DefaultDataSource implements DataSource { * Constructs a new instance, optionally configured to follow cross-protocol redirects. * * @param context A context. - * @param userAgent The User-Agent to use when requesting remote data. + * @param userAgent The user agent that will be used when requesting remote data, or {@code null} + * to use the default user agent of the underlying platform. * @param allowCrossProtocolRedirects Whether cross-protocol redirects (i.e. redirects from HTTP * to HTTPS and vice versa) are enabled when fetching remote data. */ - public DefaultDataSource(Context context, String userAgent, boolean allowCrossProtocolRedirects) { + public DefaultDataSource( + Context context, @Nullable String userAgent, boolean allowCrossProtocolRedirects) { this( context, userAgent, @@ -116,7 +117,8 @@ public final class DefaultDataSource implements DataSource { * Constructs a new instance, optionally configured to follow cross-protocol redirects. * * @param context A context. - * @param userAgent The User-Agent to use when requesting remote data. + * @param userAgent The user agent that will be used when requesting remote data, or {@code null} + * to use the default user agent of the underlying platform. * @param connectTimeoutMillis The connection timeout that should be used when requesting remote * data, in milliseconds. A timeout of zero is interpreted as an infinite timeout. * @param readTimeoutMillis The read timeout that should be used when requesting remote data, in @@ -126,7 +128,7 @@ public final class DefaultDataSource implements DataSource { */ public DefaultDataSource( Context context, - String userAgent, + @Nullable String userAgent, int connectTimeoutMillis, int readTimeoutMillis, boolean allowCrossProtocolRedirects) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSourceFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSourceFactory.java index a13008c338..0c6d210517 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSourceFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultDataSourceFactory.java @@ -15,8 +15,6 @@ */ package com.google.android.exoplayer2.upstream; -import static com.google.android.exoplayer2.ExoPlayerLibraryInfo.DEFAULT_USER_AGENT; - import android.content.Context; import androidx.annotation.Nullable; import com.google.android.exoplayer2.upstream.DataSource.Factory; @@ -37,16 +35,17 @@ public final class DefaultDataSourceFactory implements Factory { * @param context A context. */ public DefaultDataSourceFactory(Context context) { - this(context, DEFAULT_USER_AGENT, /* listener= */ null); + this(context, /* userAgent= */ (String) null, /* listener= */ null); } /** * Creates an instance. * * @param context A context. - * @param userAgent The User-Agent string that should be used. + * @param userAgent The user agent that will be used when requesting remote data, or {@code null} + * to use the default user agent of the underlying platform. */ - public DefaultDataSourceFactory(Context context, String userAgent) { + public DefaultDataSourceFactory(Context context, @Nullable String userAgent) { this(context, userAgent, /* listener= */ null); } @@ -54,11 +53,12 @@ public final class DefaultDataSourceFactory implements Factory { * Creates an instance. * * @param context A context. - * @param userAgent The User-Agent string that should be used. + * @param userAgent The user agent that will be used when requesting remote data, or {@code null} + * to use the default user agent of the underlying platform. * @param listener An optional listener. */ public DefaultDataSourceFactory( - Context context, String userAgent, @Nullable TransferListener listener) { + Context context, @Nullable String userAgent, @Nullable TransferListener listener) { this(context, listener, new DefaultHttpDataSource.Factory().setUserAgent(userAgent)); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java index c0893b85c0..9da576ea18 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSource.java @@ -15,7 +15,6 @@ */ package com.google.android.exoplayer2.upstream; -import static com.google.android.exoplayer2.ExoPlayerLibraryInfo.DEFAULT_USER_AGENT; import static java.lang.Math.max; import static java.lang.Math.min; @@ -24,7 +23,6 @@ import android.text.TextUtils; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.upstream.DataSpec.HttpMethod; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Log; @@ -69,7 +67,7 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou @Nullable private TransferListener transferListener; @Nullable private Predicate contentTypePredicate; - private String userAgent; + @Nullable private String userAgent; private int connectTimeoutMs; private int readTimeoutMs; private boolean allowCrossProtocolRedirects; @@ -77,7 +75,6 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou /** Creates an instance. */ public Factory() { defaultRequestProperties = new RequestProperties(); - userAgent = DEFAULT_USER_AGENT; connectTimeoutMs = DEFAULT_CONNECT_TIMEOUT_MILLIS; readTimeoutMs = DEFAULT_READ_TIMEOUT_MILLIS; } @@ -98,12 +95,14 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou /** * Sets the user agent that will be used. * - *

The default is {@link ExoPlayerLibraryInfo#DEFAULT_USER_AGENT}. + *

The default is {@code null}, which causes the default user agent of the underlying + * platform to be used. * - * @param userAgent The user agent that will be used. + * @param userAgent The user agent that will be used, or {@code null} to use the default user + * agent of the underlying platform. * @return This factory. */ - public Factory setUserAgent(String userAgent) { + public Factory setUserAgent(@Nullable String userAgent) { this.userAgent = userAgent; return this; } @@ -214,7 +213,7 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou private final boolean allowCrossProtocolRedirects; private final int connectTimeoutMillis; private final int readTimeoutMillis; - private final String userAgent; + @Nullable private final String userAgent; @Nullable private final RequestProperties defaultRequestProperties; private final RequestProperties requestProperties; @@ -235,23 +234,21 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou @SuppressWarnings("deprecation") @Deprecated public DefaultHttpDataSource() { - this( - ExoPlayerLibraryInfo.DEFAULT_USER_AGENT, - DEFAULT_CONNECT_TIMEOUT_MILLIS, - DEFAULT_READ_TIMEOUT_MILLIS); + this(/* userAgent= */ null, DEFAULT_CONNECT_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS); } /** @deprecated Use {@link DefaultHttpDataSource.Factory} instead. */ @SuppressWarnings("deprecation") @Deprecated - public DefaultHttpDataSource(String userAgent) { + public DefaultHttpDataSource(@Nullable String userAgent) { this(userAgent, DEFAULT_CONNECT_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS); } /** @deprecated Use {@link DefaultHttpDataSource.Factory} instead. */ @SuppressWarnings("deprecation") @Deprecated - public DefaultHttpDataSource(String userAgent, int connectTimeoutMillis, int readTimeoutMillis) { + public DefaultHttpDataSource( + @Nullable String userAgent, int connectTimeoutMillis, int readTimeoutMillis) { this( userAgent, connectTimeoutMillis, @@ -263,7 +260,7 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou /** @deprecated Use {@link DefaultHttpDataSource.Factory} instead. */ @Deprecated public DefaultHttpDataSource( - String userAgent, + @Nullable String userAgent, int connectTimeoutMillis, int readTimeoutMillis, boolean allowCrossProtocolRedirects, @@ -278,14 +275,14 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou } private DefaultHttpDataSource( - String userAgent, + @Nullable String userAgent, int connectTimeoutMillis, int readTimeoutMillis, boolean allowCrossProtocolRedirects, @Nullable RequestProperties defaultRequestProperties, @Nullable Predicate contentTypePredicate) { super(/* isNetwork= */ true); - this.userAgent = Assertions.checkNotEmpty(userAgent); + this.userAgent = userAgent; this.connectTimeoutMillis = connectTimeoutMillis; this.readTimeoutMillis = readTimeoutMillis; this.allowCrossProtocolRedirects = allowCrossProtocolRedirects; @@ -620,7 +617,9 @@ public class DefaultHttpDataSource extends BaseDataSource implements HttpDataSou } connection.setRequestProperty("Range", rangeRequest); } - connection.setRequestProperty("User-Agent", userAgent); + if (userAgent != null) { + connection.setRequestProperty("User-Agent", userAgent); + } connection.setRequestProperty("Accept-Encoding", allowGzip ? "gzip" : "identity"); connection.setInstanceFollowRedirects(followRedirects); connection.setDoOutput(httpBody != null); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSourceFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSourceFactory.java index 82fad457fb..c23e569c6c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSourceFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultHttpDataSourceFactory.java @@ -15,17 +15,15 @@ */ package com.google.android.exoplayer2.upstream; -import static com.google.android.exoplayer2.ExoPlayerLibraryInfo.DEFAULT_USER_AGENT; import androidx.annotation.Nullable; import com.google.android.exoplayer2.upstream.HttpDataSource.BaseFactory; -import com.google.android.exoplayer2.util.Assertions; /** @deprecated Use {@link DefaultHttpDataSource.Factory} instead. */ @Deprecated public final class DefaultHttpDataSourceFactory extends BaseFactory { - private final String userAgent; + @Nullable private final String userAgent; @Nullable private final TransferListener listener; private final int connectTimeoutMillis; private final int readTimeoutMillis; @@ -37,7 +35,7 @@ public final class DefaultHttpDataSourceFactory extends BaseFactory { * timeout and disables cross-protocol redirects. */ public DefaultHttpDataSourceFactory() { - this(DEFAULT_USER_AGENT); + this(/* userAgent= */ null); } /** @@ -45,9 +43,10 @@ public final class DefaultHttpDataSourceFactory extends BaseFactory { * connection timeout, {@link DefaultHttpDataSource#DEFAULT_READ_TIMEOUT_MILLIS} as the read * timeout and disables cross-protocol redirects. * - * @param userAgent The User-Agent string that should be used. + * @param userAgent The user agent that will be used, or {@code null} to use the default user + * agent of the underlying platform. */ - public DefaultHttpDataSourceFactory(String userAgent) { + public DefaultHttpDataSourceFactory(@Nullable String userAgent) { this(userAgent, null); } @@ -56,17 +55,20 @@ public final class DefaultHttpDataSourceFactory extends BaseFactory { * connection timeout, {@link DefaultHttpDataSource#DEFAULT_READ_TIMEOUT_MILLIS} as the read * timeout and disables cross-protocol redirects. * - * @param userAgent The User-Agent string that should be used. + * @param userAgent The user agent that will be used, or {@code null} to use the default user + * agent of the underlying platform. * @param listener An optional listener. * @see #DefaultHttpDataSourceFactory(String, TransferListener, int, int, boolean) */ - public DefaultHttpDataSourceFactory(String userAgent, @Nullable TransferListener listener) { + public DefaultHttpDataSourceFactory( + @Nullable String userAgent, @Nullable TransferListener listener) { this(userAgent, listener, DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS, DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, false); } /** - * @param userAgent The User-Agent string that should be used. + * @param userAgent The user agent that will be used, or {@code null} to use the default user + * agent of the underlying platform. * @param connectTimeoutMillis The connection timeout that should be used when requesting remote * data, in milliseconds. A timeout of zero is interpreted as an infinite timeout. * @param readTimeoutMillis The read timeout that should be used when requesting remote data, in @@ -75,7 +77,7 @@ public final class DefaultHttpDataSourceFactory extends BaseFactory { * to HTTPS and vice versa) are enabled. */ public DefaultHttpDataSourceFactory( - String userAgent, + @Nullable String userAgent, int connectTimeoutMillis, int readTimeoutMillis, boolean allowCrossProtocolRedirects) { @@ -88,7 +90,8 @@ public final class DefaultHttpDataSourceFactory extends BaseFactory { } /** - * @param userAgent The User-Agent string that should be used. + * @param userAgent The user agent that will be used, or {@code null} to use the default user + * agent of the underlying platform. * @param listener An optional listener. * @param connectTimeoutMillis The connection timeout that should be used when requesting remote * data, in milliseconds. A timeout of zero is interpreted as an infinite timeout. @@ -98,12 +101,12 @@ public final class DefaultHttpDataSourceFactory extends BaseFactory { * to HTTPS and vice versa) are enabled. */ public DefaultHttpDataSourceFactory( - String userAgent, + @Nullable String userAgent, @Nullable TransferListener listener, int connectTimeoutMillis, int readTimeoutMillis, boolean allowCrossProtocolRedirects) { - this.userAgent = Assertions.checkNotEmpty(userAgent); + this.userAgent = userAgent; this.listener = listener; this.connectTimeoutMillis = connectTimeoutMillis; this.readTimeoutMillis = readTimeoutMillis;