From bcd4bb87e55c6c5630ddfa5a734f79d1a534b164 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 24 Jun 2021 14:19:36 +0100 Subject: [PATCH] Deprecate CronetEngineWrapper PiperOrigin-RevId: 381239971 --- .../android/exoplayer2/demo/DemoUtil.java | 19 ++- .../cronet/CronetDataSourceContractTest.java | 37 +--- .../ext/cronet/CronetDataSource.java | 4 +- .../ext/cronet/CronetEngineWrapper.java | 122 ++----------- .../exoplayer2/ext/cronet/CronetUtil.java | 161 ++++++++++++++++++ .../ext/cronet/CronetDataSourceTest.java | 18 +- 6 files changed, 205 insertions(+), 156 deletions(-) create mode 100644 extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetUtil.java 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 080387db7e..2d3f606b8a 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 @@ -23,7 +23,7 @@ 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.CronetDataSource; -import com.google.android.exoplayer2.ext.cronet.CronetEngineWrapper; +import com.google.android.exoplayer2.ext.cronet.CronetUtil; import com.google.android.exoplayer2.offline.ActionFileUpgradeUtil; import com.google.android.exoplayer2.offline.DefaultDownloadIndex; import com.google.android.exoplayer2.offline.DownloadManager; @@ -44,6 +44,8 @@ import java.net.CookieManager; import java.net.CookiePolicy; import java.util.concurrent.Executors; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.chromium.net.CronetEngine; /** Utility methods for the demo app. */ public final class DemoUtil { @@ -102,11 +104,16 @@ public final class DemoUtil { if (httpDataSourceFactory == null) { if (USE_CRONET_FOR_NETWORKING) { context = context.getApplicationContext(); - CronetEngineWrapper cronetEngineWrapper = - new CronetEngineWrapper(context, USER_AGENT, /* preferGMSCoreCronet= */ false); - httpDataSourceFactory = - new CronetDataSource.Factory(cronetEngineWrapper, Executors.newSingleThreadExecutor()); - } else { + @Nullable + CronetEngine cronetEngine = + CronetUtil.buildCronetEngine(context, USER_AGENT, /* preferGMSCoreCronet= */ false); + if (cronetEngine != null) { + httpDataSourceFactory = + new CronetDataSource.Factory(cronetEngine, Executors.newSingleThreadExecutor()); + } + } + if (httpDataSourceFactory == null) { + // We don't want to use Cronet, or we failed to instantiate a CronetEngine. CookieManager cookieManager = new CookieManager(); cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER); CookieHandler.setDefault(cookieManager); diff --git a/extensions/cronet/src/androidTest/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceContractTest.java b/extensions/cronet/src/androidTest/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceContractTest.java index 4e18cc5e3f..71f46621d9 100644 --- a/extensions/cronet/src/androidTest/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceContractTest.java +++ b/extensions/cronet/src/androidTest/java/com/google/android/exoplayer2/ext/cronet/CronetDataSourceContractTest.java @@ -18,16 +18,16 @@ package com.google.android.exoplayer2.ext.cronet; import static com.google.common.truth.Truth.assertThat; import android.net.Uri; +import androidx.annotation.Nullable; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.testutil.DataSourceContractTest; import com.google.android.exoplayer2.testutil.HttpDataSourceTestEnv; import com.google.android.exoplayer2.upstream.DataSource; -import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.common.collect.ImmutableList; -import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import org.chromium.net.CronetEngine; import org.junit.After; import org.junit.Rule; import org.junit.runner.RunWith; @@ -46,15 +46,14 @@ public class CronetDataSourceContractTest extends DataSourceContractTest { @Override protected DataSource createDataSource() { - CronetEngineWrapper cronetEngineWrapper = - new CronetEngineWrapper( + @Nullable + CronetEngine cronetEngine = + CronetUtil.buildCronetEngine( ApplicationProvider.getApplicationContext(), /* userAgent= */ "test-agent", /* preferGMSCoreCronet= */ false); - assertThat(cronetEngineWrapper.getCronetEngine()).isNotNull(); - return new CronetDataSource.Factory(cronetEngineWrapper.getCronetEngine(), executorService) - .setFallbackFactory(new InvalidDataSourceFactory()) - .createDataSource(); + assertThat(cronetEngine).isNotNull(); + return new CronetDataSource.Factory(cronetEngine, executorService).createDataSource(); } @Override @@ -66,26 +65,4 @@ public class CronetDataSourceContractTest extends DataSourceContractTest { protected Uri getNotFoundUri() { return Uri.parse(httpDataSourceTestEnv.getNonexistentUrl()); } - - /** - * An {@link HttpDataSource.Factory} that throws {@link UnsupportedOperationException} on every - * interaction. - */ - private static class InvalidDataSourceFactory implements HttpDataSource.Factory { - @Override - public HttpDataSource createDataSource() { - throw new UnsupportedOperationException(); - } - - @Override - public HttpDataSource.RequestProperties getDefaultRequestProperties() { - throw new UnsupportedOperationException(); - } - - @Override - public HttpDataSource.Factory setDefaultRequestProperties( - Map defaultRequestProperties) { - throw new UnsupportedOperationException(); - } - } } 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 0198c87dba..47b3e1af73 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 @@ -95,7 +95,9 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource { /** * Creates an instance. * - * @param cronetEngine A {@link CronetEngine} to make the requests. + * @param cronetEngine A {@link CronetEngine} to make the requests. This should not be + * a fallback instance obtained from {@code JavaCronetProvider}. It's more efficient to use + * {@link DefaultHttpDataSource} instead in this case. * @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. 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 d5a263f052..21b90c834c 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 @@ -15,24 +15,23 @@ */ package com.google.android.exoplayer2.ext.cronet; -import static java.lang.Math.min; - import android.content.Context; import androidx.annotation.Nullable; -import com.google.android.exoplayer2.util.Log; -import com.google.android.exoplayer2.util.Util; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; import org.chromium.net.CronetEngine; import org.chromium.net.CronetProvider; -/** A wrapper class for a {@link CronetEngine}. */ +/** + * A wrapper class for a {@link CronetEngine}. + * + * @deprecated Use {@link CronetEngine} directly. See the Android developer + * guide to learn how to instantiate a {@link CronetEngine} for use by your application. You + * can also use {@link CronetUtil#buildCronetEngine} to build a {@link CronetEngine} suitable + * for use by ExoPlayer. + */ +@Deprecated public final class CronetEngineWrapper { - private static final String TAG = "CronetEngineWrapper"; - @Nullable private final CronetEngine cronetEngine; /** @@ -59,43 +58,7 @@ public final class CronetEngineWrapper { */ public CronetEngineWrapper( Context context, @Nullable String userAgent, boolean preferGMSCoreCronet) { - @Nullable CronetEngine cronetEngine = null; - List cronetProviders = new ArrayList<>(CronetProvider.getAllProviders(context)); - // Remove disabled and fallback Cronet providers from list - for (int i = cronetProviders.size() - 1; i >= 0; i--) { - if (!cronetProviders.get(i).isEnabled() - || CronetProvider.PROVIDER_NAME_FALLBACK.equals(cronetProviders.get(i).getName())) { - cronetProviders.remove(i); - } - } - // Sort remaining providers by type and version. - CronetProviderComparator providerComparator = new CronetProviderComparator(preferGMSCoreCronet); - Collections.sort(cronetProviders, providerComparator); - for (int i = 0; i < cronetProviders.size() && cronetEngine == null; i++) { - String providerName = cronetProviders.get(i).getName(); - try { - CronetEngine.Builder cronetEngineBuilder = cronetProviders.get(i).createBuilder(); - if (userAgent != null) { - cronetEngineBuilder.setUserAgent(userAgent); - } - cronetEngine = cronetEngineBuilder.build(); - Log.d(TAG, "CronetEngine built using " + providerName); - } catch (SecurityException e) { - Log.w( - TAG, - "Failed to build CronetEngine. Please check if current process has " - + "android.permission.ACCESS_NETWORK_STATE."); - } catch (UnsatisfiedLinkError e) { - Log.w( - TAG, - "Failed to link Cronet binaries. Please check if native Cronet binaries are " - + "bundled into your app."); - } - } - if (cronetEngine == null) { - Log.w(TAG, "CronetEngine could not be built."); - } - this.cronetEngine = cronetEngine; + cronetEngine = CronetUtil.buildCronetEngine(context, userAgent, preferGMSCoreCronet); } /** @@ -116,67 +79,4 @@ public final class CronetEngineWrapper { /* package */ CronetEngine getCronetEngine() { return cronetEngine; } - - private static class CronetProviderComparator implements Comparator { - - /* - * Copy of com.google.android.gms.net.CronetProviderInstaller.PROVIDER_NAME. We have our own - * copy because GMSCore CronetProvider classes are unavailable in some (internal to Google) - * build configurations. - */ - private static final String GMS_CORE_PROVIDER_NAME = "Google-Play-Services-Cronet-Provider"; - - private final boolean preferGMSCoreCronet; - - public CronetProviderComparator(boolean preferGMSCoreCronet) { - this.preferGMSCoreCronet = preferGMSCoreCronet; - } - - @Override - public int compare(CronetProvider providerLeft, CronetProvider providerRight) { - int providerComparison = getPriority(providerLeft) - getPriority(providerRight); - if (providerComparison != 0) { - return providerComparison; - } - return -compareVersionStrings(providerLeft.getVersion(), providerRight.getVersion()); - } - - /** - * Returns the priority score for a Cronet provider, where a smaller score indicates higher - * priority. - */ - private int getPriority(CronetProvider provider) { - String providerName = provider.getName(); - if (CronetProvider.PROVIDER_NAME_APP_PACKAGED.equals(providerName)) { - return 1; - } else if (GMS_CORE_PROVIDER_NAME.equals(providerName)) { - return preferGMSCoreCronet ? 0 : 2; - } else { - return 3; - } - } - - /** Compares version strings of format "12.123.35.23". */ - private static int compareVersionStrings( - @Nullable String versionLeft, @Nullable String versionRight) { - if (versionLeft == null || versionRight == null) { - return 0; - } - String[] versionStringsLeft = Util.split(versionLeft, "\\."); - String[] versionStringsRight = Util.split(versionRight, "\\."); - int minLength = min(versionStringsLeft.length, versionStringsRight.length); - for (int i = 0; i < minLength; i++) { - if (!versionStringsLeft[i].equals(versionStringsRight[i])) { - try { - int versionIntLeft = Integer.parseInt(versionStringsLeft[i]); - int versionIntRight = Integer.parseInt(versionStringsRight[i]); - return versionIntLeft - versionIntRight; - } catch (NumberFormatException e) { - return 0; - } - } - } - return 0; - } - } } diff --git a/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetUtil.java b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetUtil.java new file mode 100644 index 0000000000..05dda1ff0b --- /dev/null +++ b/extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetUtil.java @@ -0,0 +1,161 @@ +/* + * Copyright 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.ext.cronet; + +import static java.lang.Math.min; + +import android.content.Context; +import androidx.annotation.Nullable; +import com.google.android.exoplayer2.upstream.DefaultHttpDataSource; +import com.google.android.exoplayer2.util.Log; +import com.google.android.exoplayer2.util.Util; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import org.chromium.net.CronetEngine; +import org.chromium.net.CronetProvider; + +/** Cronet utility methods. */ +public final class CronetUtil { + + private static final String TAG = "CronetUtil"; + + /** + * Builds a {@link CronetEngine} suitable for use with ExoPlayer. When choosing a {@link + * CronetProvider Cronet provider} to build the {@link CronetEngine}, disabled providers are not + * considered. Neither are fallback providers, since it's more efficient to use {@link + * DefaultHttpDataSource} than it is to use {@link CronetDataSource} with a fallback {@link + * CronetEngine}. + * + *

Note that it's recommended for applications to create only one instance of {@link + * CronetEngine}, so if your application already has an instance for performing other networking, + * then that instance should be used and calling this method is unnecessary. See the Android developer + * guide to learn more about using Cronet for network operations. + * + * @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. + * @return The {@link CronetEngine}, or {@code null} if no suitable engine could be built. + */ + @Nullable + public static CronetEngine buildCronetEngine( + Context context, @Nullable String userAgent, boolean preferGMSCoreCronet) { + List cronetProviders = new ArrayList<>(CronetProvider.getAllProviders(context)); + // Remove disabled and fallback Cronet providers from list. + for (int i = cronetProviders.size() - 1; i >= 0; i--) { + if (!cronetProviders.get(i).isEnabled() + || CronetProvider.PROVIDER_NAME_FALLBACK.equals(cronetProviders.get(i).getName())) { + cronetProviders.remove(i); + } + } + // Sort remaining providers by type and version. + CronetProviderComparator providerComparator = new CronetProviderComparator(preferGMSCoreCronet); + Collections.sort(cronetProviders, providerComparator); + for (int i = 0; i < cronetProviders.size(); i++) { + String providerName = cronetProviders.get(i).getName(); + try { + CronetEngine.Builder cronetEngineBuilder = cronetProviders.get(i).createBuilder(); + if (userAgent != null) { + cronetEngineBuilder.setUserAgent(userAgent); + } + CronetEngine cronetEngine = cronetEngineBuilder.build(); + Log.d(TAG, "CronetEngine built using " + providerName); + return cronetEngine; + } catch (SecurityException e) { + Log.w( + TAG, + "Failed to build CronetEngine. Please check if current process has " + + "android.permission.ACCESS_NETWORK_STATE."); + } catch (UnsatisfiedLinkError e) { + Log.w( + TAG, + "Failed to link Cronet binaries. Please check if native Cronet binaries are " + + "bundled into your app."); + } + } + Log.w(TAG, "CronetEngine could not be built."); + return null; + } + + private CronetUtil() {} + + private static class CronetProviderComparator implements Comparator { + + /* + * Copy of com.google.android.gms.net.CronetProviderInstaller.PROVIDER_NAME. We have our own + * copy because GMSCore CronetProvider classes are unavailable in some (internal to Google) + * build configurations. + */ + private static final String GMS_CORE_PROVIDER_NAME = "Google-Play-Services-Cronet-Provider"; + + private final boolean preferGMSCoreCronet; + + public CronetProviderComparator(boolean preferGMSCoreCronet) { + this.preferGMSCoreCronet = preferGMSCoreCronet; + } + + @Override + public int compare(CronetProvider providerLeft, CronetProvider providerRight) { + int providerComparison = getPriority(providerLeft) - getPriority(providerRight); + if (providerComparison != 0) { + return providerComparison; + } + return -compareVersionStrings(providerLeft.getVersion(), providerRight.getVersion()); + } + + /** + * Returns the priority score for a Cronet provider, where a smaller score indicates higher + * priority. + */ + private int getPriority(CronetProvider provider) { + String providerName = provider.getName(); + if (CronetProvider.PROVIDER_NAME_APP_PACKAGED.equals(providerName)) { + return 1; + } else if (GMS_CORE_PROVIDER_NAME.equals(providerName)) { + return preferGMSCoreCronet ? 0 : 2; + } else { + return 3; + } + } + + /** Compares version strings of format "12.123.35.23". */ + private static int compareVersionStrings( + @Nullable String versionLeft, @Nullable String versionRight) { + if (versionLeft == null || versionRight == null) { + return 0; + } + String[] versionStringsLeft = Util.split(versionLeft, "\\."); + String[] versionStringsRight = Util.split(versionRight, "\\."); + int minLength = min(versionStringsLeft.length, versionStringsRight.length); + for (int i = 0; i < minLength; i++) { + if (!versionStringsLeft[i].equals(versionStringsRight[i])) { + try { + int versionIntLeft = Integer.parseInt(versionStringsLeft[i]); + int versionIntRight = Integer.parseInt(versionStringsRight[i]); + return versionIntLeft - versionIntRight; + } catch (NumberFormatException e) { + return 0; + } + } + } + return 0; + } + } +} 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 4d2429b3c1..de54242b8a 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 @@ -34,7 +34,6 @@ 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.upstream.DataSpec; @@ -119,7 +118,7 @@ public final class CronetDataSourceTest { executorService = Executors.newSingleThreadExecutor(); dataSourceUnderTest = (CronetDataSource) - new CronetDataSource.Factory(new CronetEngineWrapper(mockCronetEngine), executorService) + new CronetDataSource.Factory(mockCronetEngine, executorService) .setConnectionTimeoutMs(TEST_CONNECT_TIMEOUT_MS) .setReadTimeoutMs(TEST_READ_TIMEOUT_MS) .setResetTimeoutOnRedirects(true) @@ -1174,7 +1173,7 @@ public final class CronetDataSourceTest { throws HttpDataSourceException { dataSourceUnderTest = (CronetDataSource) - new CronetDataSource.Factory(new CronetEngineWrapper(mockCronetEngine), executorService) + new CronetDataSource.Factory(mockCronetEngine, executorService) .setConnectionTimeoutMs(TEST_CONNECT_TIMEOUT_MS) .setReadTimeoutMs(TEST_READ_TIMEOUT_MS) .setResetTimeoutOnRedirects(true) @@ -1202,7 +1201,7 @@ public final class CronetDataSourceTest { testDataSpec = new DataSpec(Uri.parse(TEST_URL), 1000, 5000); dataSourceUnderTest = (CronetDataSource) - new CronetDataSource.Factory(new CronetEngineWrapper(mockCronetEngine), executorService) + new CronetDataSource.Factory(mockCronetEngine, executorService) .setConnectionTimeoutMs(TEST_CONNECT_TIMEOUT_MS) .setReadTimeoutMs(TEST_READ_TIMEOUT_MS) .setResetTimeoutOnRedirects(true) @@ -1239,7 +1238,7 @@ public final class CronetDataSourceTest { throws HttpDataSourceException { dataSourceUnderTest = (CronetDataSource) - new CronetDataSource.Factory(new CronetEngineWrapper(mockCronetEngine), executorService) + new CronetDataSource.Factory(mockCronetEngine, executorService) .setConnectionTimeoutMs(TEST_CONNECT_TIMEOUT_MS) .setReadTimeoutMs(TEST_READ_TIMEOUT_MS) .setResetTimeoutOnRedirects(true) @@ -1450,6 +1449,7 @@ public final class CronetDataSourceTest { verify(mockUrlRequestBuilder).allowDirectExecutor(); } + @SuppressWarnings("deprecation") // Tests deprecated fallback functionality. @Test public void factorySetFallbackHttpDataSourceFactory_cronetNotAvailable_usesFallbackFactory() throws HttpDataSourceException, InterruptedException { @@ -1470,10 +1470,11 @@ public final class CronetDataSourceTest { assertThat(headers.get("user-agent")).isEqualTo("customFallbackFactoryUserAgent"); } + @SuppressWarnings("deprecation") // Tests deprecated fallback functionality. @Test public void factory_noFallbackFactoryCronetNotAvailable_delegateTransferListenerToInternalFallbackFactory() - throws HttpDataSourceException, InterruptedException { + throws HttpDataSourceException { MockWebServer mockWebServer = new MockWebServer(); mockWebServer.enqueue(new MockResponse()); CronetEngineWrapper cronetEngineWrapper = new CronetEngineWrapper((CronetEngine) null); @@ -1492,14 +1493,14 @@ public final class CronetDataSourceTest { .onTransferStart(eq(dataSourceUnderTest), eq(dataSpec), /* isNetwork= */ eq(true)); } + @SuppressWarnings("deprecation") // Tests deprecated fallback functionality. @Test public void factory_noFallbackFactoryCronetNotAvailable_delegateDefaultRequestPropertiesToInternalFallbackFactory() throws HttpDataSourceException, InterruptedException { MockWebServer mockWebServer = new MockWebServer(); mockWebServer.enqueue(new MockResponse()); - CronetEngineWrapper cronetEngineWrapper = - new CronetEngineWrapper(ApplicationProvider.getApplicationContext()); + CronetEngineWrapper cronetEngineWrapper = new CronetEngineWrapper((CronetEngine) null); Map defaultRequestProperties = new HashMap<>(); defaultRequestProperties.put("0", "defaultRequestProperty0"); HttpDataSource dataSourceUnderTest = @@ -1515,6 +1516,7 @@ public final class CronetDataSourceTest { assertThat(dataSourceUnderTest).isInstanceOf(DefaultHttpDataSource.class); } + @SuppressWarnings("deprecation") // Tests deprecated fallback functionality. @Test public void factory_noFallbackFactoryCronetNotAvailable_delegateDefaultRequestPropertiesToInternalFallbackFactoryAfterCreation()