• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.android.libraries.mobiledatadownload.downloader.offroad.dagger.downloader2;
17 
18 import static com.google.common.util.concurrent.Futures.immediateFuture;
19 
20 import android.content.Context;
21 
22 import com.google.android.downloader.AndroidConnectivityHandler;
23 import com.google.android.downloader.Downloader;
24 import com.google.android.downloader.Downloader.StateChangeCallback;
25 import com.google.android.downloader.FloggerDownloaderLogger;
26 import com.google.android.downloader.PlatformUrlEngine;
27 import com.google.android.downloader.UrlEngine;
28 import com.google.android.libraries.mobiledatadownload.Flags;
29 import com.google.android.libraries.mobiledatadownload.annotations.MddControlExecutor;
30 import com.google.android.libraries.mobiledatadownload.annotations.MddDownloadExecutor;
31 import com.google.android.libraries.mobiledatadownload.annotations.SocketTrafficTag;
32 import com.google.android.libraries.mobiledatadownload.downloader.FileDownloader;
33 import com.google.android.libraries.mobiledatadownload.downloader.OAuthTokenProvider;
34 import com.google.android.libraries.mobiledatadownload.downloader.offroad.ExceptionHandler;
35 import com.google.android.libraries.mobiledatadownload.downloader.offroad.Offroad2FileDownloader;
36 import com.google.android.libraries.mobiledatadownload.downloader.offroad.dagger.BaseOffroadFileDownloaderModule;
37 import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage;
38 import com.google.android.libraries.mobiledatadownload.file.integration.downloader.DownloadMetadataStore;
39 import com.google.android.libraries.mobiledatadownload.monitor.DownloadProgressMonitor;
40 import com.google.common.base.Optional;
41 import com.google.common.base.Supplier;
42 import com.google.common.util.concurrent.ListeningExecutorService;
43 
44 import java.util.concurrent.ScheduledExecutorService;
45 
46 import javax.annotation.Nullable;
47 import javax.inject.Singleton;
48 
49 import dagger.Lazy;
50 import dagger.Module;
51 import dagger.Provides;
52 import dagger.multibindings.IntoMap;
53 import dagger.multibindings.StringKey;
54 
55 /**
56  * Dagger module for providing FileDownloader that uses Android Downloader2.
57  *
58  * <p>This module should only be used when {@link MultiSchemeFileDownloader} is being provided by
59  * {@link FileDownloaderModule}. That module includes a map of FileDownloader Suppliers, which this
60  * module assumes is available to bind into.
61  */
62 @Module(
63         includes = {
64                 BaseOffroadFileDownloaderModule.class,
65                 BaseFileDownloaderDepsModule.class,
66         })
67 public abstract class BaseFileDownloaderModule {
68     @Provides
69     @Singleton
70     @IntoMap
71     @StringKey("https")
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)72     static Supplier<FileDownloader> provideFileDownloader(
73             Context context,
74             @MddDownloadExecutor ScheduledExecutorService downloadExecutor,
75             @MddControlExecutor ListeningExecutorService controlExecutor,
76             SynchronousFileStorage fileStorage,
77             DownloadMetadataStore downloadMetadataStore,
78             Optional<DownloadProgressMonitor> downloadProgressMonitor,
79             Optional<Lazy<UrlEngine>> urlEngineOptional,
80             Optional<Lazy<ExceptionHandler>> exceptionHandlerOptional,
81             Optional<Lazy<OAuthTokenProvider>> authTokenProviderOptional,
82 //      Optional<Supplier<CookieJar>> cookieJarSupplierOptional,
83             @SocketTrafficTag Optional<Integer> trafficTag,
84             Flags flags) {
85         return () ->
86                 createOffroad2FileDownloader(
87                         context,
88                         downloadExecutor,
89                         controlExecutor,
90                         fileStorage,
91                         downloadMetadataStore,
92                         downloadProgressMonitor,
93                         urlEngineOptional,
94                         exceptionHandlerOptional,
95                         authTokenProviderOptional,
96 //            cookieJarSupplierOptional,
97                         trafficTag,
98                         flags);
99     }
100 
101     /**
102      * Manual provider of Offroad2FileDownloader.
103      *
104      * <p>NOTE: This method should only be used when manually wiring up dependencies, such as when
105      * dagger/hilt are not available. If using dagger/hilt, this method is not needed. By
106      * registering
107      * this module in the dagger graph, the above @Provides method will automatically provide this
108      * dependency.
109      */
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)110     public static Offroad2FileDownloader createOffroad2FileDownloader(
111             Context context,
112             ScheduledExecutorService downloadExecutor,
113             ListeningExecutorService controlExecutor,
114             SynchronousFileStorage fileStorage,
115             DownloadMetadataStore downloadMetadataStore,
116             Optional<DownloadProgressMonitor> downloadProgressMonitor,
117             Optional<Lazy<UrlEngine>> urlEngineOptional,
118             Optional<Lazy<ExceptionHandler>> exceptionHandlerOptional,
119             Optional<Lazy<OAuthTokenProvider>> authTokenProviderOptional,
120 //      Optional<Supplier<CookieJar>> cookieJarSupplierOptional,
121             Optional<Integer> trafficTag,
122             Flags flags) {
123         @Nullable
124         com.google.android.downloader.OAuthTokenProvider authTokenProvider =
125                 authTokenProviderOptional.isPresent()
126                         ? convertToDownloaderAuthTokenProvider(
127                         authTokenProviderOptional.get().get())
128                         : null;
129 
130         ExceptionHandler handler =
131                 exceptionHandlerOptional.transform(Lazy::get).or(
132                         ExceptionHandler.withDefaultHandling());
133 
134         UrlEngine urlEngine;
135         if (urlEngineOptional.isPresent()) {
136             urlEngine = urlEngineOptional.get().get();
137         } else {
138             // Use {@link PlatformUrlEngine} if one was not provided.
139             urlEngine =
140                     new PlatformUrlEngine(
141                             controlExecutor,
142                             /* connectTimeoutMs = */ flags.timeToWaitForDownloader(),
143                             /* readTimeoutMs = */ flags.timeToWaitForDownloader()
144                     );
145         }
146 
147         AndroidConnectivityHandler connectivityHandler =
148                 new AndroidConnectivityHandler(
149                         context, downloadExecutor, /* timeoutMillis= */
150                         flags.timeToWaitForDownloader());
151 
152         FloggerDownloaderLogger logger = new FloggerDownloaderLogger();
153 
154         Downloader downloader =
155                 new Downloader.Builder()
156                         .withIOExecutor(controlExecutor)
157                         .withConnectivityHandler(connectivityHandler)
158                         .withMaxConcurrentDownloads(flags.downloaderMaxThreads())
159                         .withLogger(logger)
160                         .addUrlEngine("https", urlEngine)
161                         .build();
162 
163         if (downloadProgressMonitor.isPresent()) {
164             // Wire up downloader's state changes to DownloadProgressMonitor to handle connectivity
165             // pauses.
166             StateChangeCallback callback =
167                     state -> {
168                         if (state.getNumDownloadsPendingConnectivity() > 0
169                                 && state.getNumDownloadsInFlight() == 0) {
170                             // Handle network connectivity pauses
171                             downloadProgressMonitor.get().pausedForConnectivity();
172                         }
173                     };
174             downloader.registerStateChangeCallback(callback, controlExecutor);
175         }
176 
177         return new Offroad2FileDownloader(
178                 downloader,
179                 fileStorage,
180                 downloadExecutor,
181                 authTokenProvider,
182                 downloadMetadataStore,
183                 handler,
184 //        cookieJarSupplierOptional,
185                 trafficTag);
186     }
187 
188     private static com.google.android.downloader.OAuthTokenProvider
convertToDownloaderAuthTokenProvider(OAuthTokenProvider authTokenProvider)189     convertToDownloaderAuthTokenProvider(OAuthTokenProvider authTokenProvider) {
190         return uri -> immediateFuture(authTokenProvider.provideOAuthToken(uri.toString()));
191     }
192 
BaseFileDownloaderModule()193     private BaseFileDownloaderModule() {
194     }
195 }
196