blob: 425608c3c746a32a7e654f3bb49632c50a9c9bb1 [file] [log] [blame]
/*
* Copyright 2022 Google LLC
*
* 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.libraries.mobiledatadownload.downloader.offroad.dagger.downloader2;
import static com.google.common.util.concurrent.Futures.immediateFuture;
import android.content.Context;
import androidx.annotation.VisibleForTesting;
import com.google.android.downloader.AndroidConnectivityHandler;
import com.google.android.downloader.Downloader;
import com.google.android.downloader.Downloader.StateChangeCallback;
import com.google.android.downloader.FloggerDownloaderLogger;
import com.google.android.downloader.PlatformAndroidTrafficStatsTagger;
import com.google.android.downloader.PlatformUrlEngine;
import com.google.android.downloader.UrlEngine;
import com.google.android.libraries.mobiledatadownload.Flags;
import com.google.android.libraries.mobiledatadownload.annotations.MddControlExecutor;
import com.google.android.libraries.mobiledatadownload.annotations.MddDownloadExecutor;
import com.google.android.libraries.mobiledatadownload.annotations.SocketTrafficTag;
import com.google.android.libraries.mobiledatadownload.downloader.FileDownloader;
import com.google.android.libraries.mobiledatadownload.downloader.OAuthTokenProvider;
import com.google.android.libraries.mobiledatadownload.downloader.offroad.ExceptionHandler;
import com.google.android.libraries.mobiledatadownload.downloader.offroad.Offroad2FileDownloader;
import com.google.android.libraries.mobiledatadownload.downloader.offroad.dagger.BaseOffroadFileDownloaderModule;
import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage;
import com.google.android.libraries.mobiledatadownload.file.integration.downloader.DownloadMetadataStore;
import com.google.android.libraries.mobiledatadownload.monitor.DownloadProgressMonitor;
import com.google.common.base.Optional;
import com.google.common.base.Supplier;
import com.google.common.util.concurrent.ListeningExecutorService;
import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
import java.util.concurrent.ScheduledExecutorService;
import javax.annotation.Nullable;
import javax.inject.Singleton;
/**
* Dagger module for providing FileDownloader that uses Android Downloader2.
*
* <p>This module should only be used when {@link MultiSchemeFileDownloader} is being provided by
* {@link FileDownloaderModule}. That module includes a map of FileDownloader Suppliers, which this
* module assumes is available to bind into.
*/
@Module(
includes = {
BaseOffroadFileDownloaderModule.class,
BaseFileDownloaderDepsModule.class,
})
@VisibleForTesting
public abstract class BaseFileDownloaderModule {
@Provides
@Singleton
@IntoMap
@StringKey("https")
static Supplier<FileDownloader> provideFileDownloader(
Context context,
@MddDownloadExecutor ScheduledExecutorService downloadExecutor,
@MddControlExecutor ListeningExecutorService controlExecutor,
SynchronousFileStorage fileStorage,
DownloadMetadataStore downloadMetadataStore,
Optional<DownloadProgressMonitor> downloadProgressMonitor,
Optional<Lazy<UrlEngine>> urlEngineOptional,
Optional<Lazy<ExceptionHandler>> exceptionHandlerOptional,
Optional<Lazy<OAuthTokenProvider>> authTokenProviderOptional,
@SocketTrafficTag Optional<Integer> trafficTag,
Flags flags) {
return () ->
createOffroad2FileDownloader(
context,
downloadExecutor,
controlExecutor,
fileStorage,
downloadMetadataStore,
downloadProgressMonitor,
urlEngineOptional,
exceptionHandlerOptional,
authTokenProviderOptional,
trafficTag,
flags);
}
@VisibleForTesting
public static Offroad2FileDownloader createOffroad2FileDownloader(
Context context,
ScheduledExecutorService downloadExecutor,
ListeningExecutorService controlExecutor,
SynchronousFileStorage fileStorage,
DownloadMetadataStore downloadMetadataStore,
Optional<DownloadProgressMonitor> downloadProgressMonitor,
Optional<Lazy<UrlEngine>> urlEngineOptional,
Optional<Lazy<ExceptionHandler>> exceptionHandlerOptional,
Optional<Lazy<OAuthTokenProvider>> authTokenProviderOptional,
Optional<Integer> trafficTag,
Flags flags) {
@Nullable
com.google.android.downloader.OAuthTokenProvider authTokenProvider =
authTokenProviderOptional.isPresent()
? convertToDownloaderAuthTokenProvider(authTokenProviderOptional.get().get())
: null;
ExceptionHandler handler =
exceptionHandlerOptional.transform(Lazy::get).or(ExceptionHandler.withDefaultHandling());
UrlEngine urlEngine;
if (urlEngineOptional.isPresent()) {
urlEngine = urlEngineOptional.get().get();
} else {
// Use {@link PlatformUrlEngine} if one was not provided.
urlEngine =
new PlatformUrlEngine(
controlExecutor,
/* connectTimeoutMs = */ flags.timeToWaitForDownloader(),
/* readTimeoutMs = */ flags.timeToWaitForDownloader(),
new PlatformAndroidTrafficStatsTagger());
}
AndroidConnectivityHandler connectivityHandler =
new AndroidConnectivityHandler(
context, downloadExecutor, /* timeoutMillis = */ flags.timeToWaitForDownloader());
FloggerDownloaderLogger logger = new FloggerDownloaderLogger();
Downloader downloader =
new Downloader.Builder()
.withIOExecutor(controlExecutor)
.withConnectivityHandler(connectivityHandler)
.withMaxConcurrentDownloads(flags.downloaderMaxThreads())
.withLogger(logger)
.addUrlEngine("https", urlEngine)
.build();
if (downloadProgressMonitor.isPresent()) {
// Wire up downloader's state changes to DownloadProgressMonitor to handle connectivity
// pauses.
StateChangeCallback callback =
state -> {
if (state.getNumDownloadsPendingConnectivity() > 0
&& state.getNumDownloadsInFlight() == 0) {
// Handle network connectivity pauses
downloadProgressMonitor.get().pausedForConnectivity();
}
};
downloader.registerStateChangeCallback(callback, controlExecutor);
}
return new Offroad2FileDownloader(
downloader,
fileStorage,
downloadExecutor,
authTokenProvider,
downloadMetadataStore,
handler,
trafficTag);
}
private static com.google.android.downloader.OAuthTokenProvider
convertToDownloaderAuthTokenProvider(OAuthTokenProvider authTokenProvider) {
return uri -> immediateFuture(authTokenProvider.provideOAuthToken(uri.toString()));
}
private BaseFileDownloaderModule() {}
}