/* * Copyright (C) 2016 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.example.exoplayertv; import android.content.Context; import androidx.media3.common.util.UnstableApi; import androidx.media3.exoplayer.DefaultRenderersFactory; import androidx.media3.exoplayer.RenderersFactory; import androidx.media3.database.DatabaseProvider; import androidx.media3.database.StandaloneDatabaseProvider; import androidx.media3.datasource.cronet.CronetDataSource; import androidx.media3.datasource.cronet.CronetUtil; import androidx.media3.exoplayer.offline.DownloadManager; import androidx.media3.exoplayer.offline.DownloadNotificationHelper; import androidx.media3.datasource.DataSource; import androidx.media3.datasource.DefaultDataSource; import androidx.media3.datasource.DefaultHttpDataSource; import androidx.media3.datasource.cache.Cache; import androidx.media3.datasource.cache.CacheDataSource; import androidx.media3.datasource.cache.NoOpCacheEvictor; import androidx.media3.datasource.cache.SimpleCache; import java.io.File; import java.net.CookieHandler; 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 { public static final String DOWNLOAD_NOTIFICATION_CHANNEL_ID = "download_channel"; /** * Whether the demo application uses Cronet for networking. Note that Cronet does not provide * automatic support for cookies (https://github.com/google/ExoPlayer/issues/5975). * *

If set to false, the platform's default network stack is used with a {@link CookieManager} * configured in {@link #getHttpDataSourceFactory}. */ private static final boolean USE_CRONET_FOR_NETWORKING = true; private static final String TAG = "DemoUtil"; private static final String DOWNLOAD_CONTENT_DIRECTORY = "downloads"; private static DataSource.@MonotonicNonNull Factory dataSourceFactory; private static DataSource.@MonotonicNonNull Factory httpDataSourceFactory; @UnstableApi private static @MonotonicNonNull DatabaseProvider databaseProvider; private static @MonotonicNonNull File downloadDirectory; @UnstableApi private static @MonotonicNonNull Cache downloadCache; @UnstableApi private static @MonotonicNonNull DownloadManager downloadManager; private static @MonotonicNonNull DownloadTracker downloadTracker; @UnstableApi private static @MonotonicNonNull DownloadNotificationHelper downloadNotificationHelper; /** Returns whether extension renderers should be used. */ public static boolean useExtensionRenderers() { return false; // Elmar: BuildConfig.USE_DECODER_EXTENSIONS; } @UnstableApi public static RenderersFactory buildRenderersFactory( Context context, boolean preferExtensionRenderer) { @DefaultRenderersFactory.ExtensionRendererMode int extensionRendererMode = useExtensionRenderers() ? (preferExtensionRenderer ? DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER : DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON) : DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF; return new DefaultRenderersFactory(context.getApplicationContext()) .setExtensionRendererMode(extensionRendererMode); } public static synchronized DataSource.Factory getHttpDataSourceFactory(Context context) { if (httpDataSourceFactory == null) { if (USE_CRONET_FOR_NETWORKING) { context = context.getApplicationContext(); @Nullable CronetEngine cronetEngine = CronetUtil.buildCronetEngine(context); 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); httpDataSourceFactory = new DefaultHttpDataSource.Factory(); } } return httpDataSourceFactory; } /** Returns a {@link DataSource.Factory}. */ @UnstableApi public static synchronized DataSource.Factory getDataSourceFactory(Context context) { if (dataSourceFactory == null) { context = context.getApplicationContext(); DefaultDataSource.Factory upstreamFactory = new DefaultDataSource.Factory(context, getHttpDataSourceFactory(context)); dataSourceFactory = buildReadOnlyCacheDataSource(upstreamFactory, getDownloadCache(context)); } return dataSourceFactory; } @UnstableApi public static synchronized DownloadNotificationHelper getDownloadNotificationHelper( Context context) { if (downloadNotificationHelper == null) { downloadNotificationHelper = new DownloadNotificationHelper(context, DOWNLOAD_NOTIFICATION_CHANNEL_ID); } return downloadNotificationHelper; } @UnstableApi public static synchronized DownloadManager getDownloadManager(Context context) { ensureDownloadManagerInitialized(context); return downloadManager; } @UnstableApi public static synchronized DownloadTracker getDownloadTracker(Context context) { ensureDownloadManagerInitialized(context); return downloadTracker; } @UnstableApi private static synchronized Cache getDownloadCache(Context context) { if (downloadCache == null) { File downloadContentDirectory = new File(getDownloadDirectory(context), DOWNLOAD_CONTENT_DIRECTORY); downloadCache = new SimpleCache( downloadContentDirectory, new NoOpCacheEvictor(), getDatabaseProvider(context)); } return downloadCache; } @UnstableApi private static synchronized void ensureDownloadManagerInitialized(Context context) { if (downloadManager == null) { downloadManager = new DownloadManager( context, getDatabaseProvider(context), getDownloadCache(context), getHttpDataSourceFactory(context), Executors.newFixedThreadPool(/* nThreads= */ 6)); downloadTracker = new DownloadTracker(context, getHttpDataSourceFactory(context), downloadManager); } } @UnstableApi private static synchronized DatabaseProvider getDatabaseProvider(Context context) { if (databaseProvider == null) { databaseProvider = new StandaloneDatabaseProvider(context); } return databaseProvider; } private static synchronized File getDownloadDirectory(Context context) { if (downloadDirectory == null) { downloadDirectory = context.getExternalFilesDir(/* type= */ null); if (downloadDirectory == null) { downloadDirectory = context.getFilesDir(); } } return downloadDirectory; } @UnstableApi private static CacheDataSource.Factory buildReadOnlyCacheDataSource( DataSource.Factory upstreamFactory, Cache cache) { return new CacheDataSource.Factory() .setCache(cache) .setUpstreamDataSourceFactory(upstreamFactory) .setCacheWriteDataSinkFactory(null) .setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR); } private DemoUtil() {} }