blob: 208132c1afe8713b7317924d00e85c975746d5a4 [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.lite;
import android.content.Context;
import com.google.android.libraries.mobiledatadownload.downloader.FileDownloader;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Supplier;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.errorprone.annotations.CheckReturnValue;
import java.util.concurrent.Executor;
/** The root object and entry point for the MDDLite (<internal>). */
public interface Downloader {
/**
* Downloads a file with the given {@link DownloadRequest}.
*
* <p>This method will not create a notification and will not run in a ForegroundService.
*
* <p>NOTE: The caller is responsible for keeping the download alive. This is typically used by
* clients who use a service the platform binds with, so a notification is not needed. If you are
* unsure whether to use this method or {@link #downloadWithForegroundService}, contact the MDD
* team (<internal>@ or via <a href="<internal>">yaqs</a>.
*/
@CheckReturnValue
ListenableFuture<Void> download(DownloadRequest downloadRequest);
/**
* Download a file and show foreground download progress in a notification. User can cancel the
* download from the notification menu.
*
* <p>NOTE: Calling downloadWithForegroundService without a provided ForegroundService will return
* a failed future.
*
* <p>The cancel action in the notification menu requires the ForegroundService to be registered
* with the application (via the AndroidManifest.xml). This allows the cancellation intents to be
* properly picked up. To register the service, the following lines must be included in the app's
* {@code AndroidManifest.xml}:
*
* <pre>{@code
* <!-- Needed by foreground download service -->
* <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
*
* <!-- Service for MDD Lite foreground downloads -->
* <service
* android:name="com.google.android.libraries.mobiledatadownload.lite.sting.ForegroundDownloadService"
* android:exported="false" />
* }</pre>
*
* <p>NOTE: The above excerpt is for Framework and Sting apps. Dagger apps should use the same
* excerpt, but change the {@code android:name} property to:
*
* <pre>{@code
* android:name="com.google.android.libraries.mobiledatadownload.lite.dagger.ForegroundDownloadService"
* }</pre>
*/
@CheckReturnValue
ListenableFuture<Void> downloadWithForegroundService(DownloadRequest downloadRequest);
/** Cancel an on-going foreground download. */
void cancelForegroundDownload(String destinationFileUri);
static Downloader.Builder newBuilder() {
return new Downloader.Builder();
}
/** A Builder for the {@link Downloader}. */
final class Builder {
private static final String TAG = "Builder";
private Executor sequentialControlExecutor;
private Context context;
private Supplier<FileDownloader> fileDownloaderSupplier;
private Optional<SingleFileDownloadProgressMonitor> downloadMonitorOptional = Optional.absent();
private Optional<Class<?>> foregroundDownloadServiceClassOptional = Optional.absent();
public Builder setContext(Context context) {
this.context = context.getApplicationContext();
return this;
}
/** Set the Control Executor which will run MDDLite control flow. */
public Builder setControlExecutor(Executor controlExecutor) {
Preconditions.checkNotNull(controlExecutor);
// Executor that will execute tasks sequentially.
this.sequentialControlExecutor = MoreExecutors.newSequentialExecutor(controlExecutor);
return this;
}
/**
* Set the SingleFileDownloadProgressMonitor. This instance must be the same instance that is
* registered with SynchronousFileStorage.
*
* <p>This is required to use {@link Downloader#downloadWithForegroundService}. Not providing
* this will result in a failed future when calling downloadWithForegroundService.
*
* <p>This is required to track progress updates and network pauses when passing a {@link
* DownloadListener} to {@link Downloader#download}. The DownloadListener's {@code onFailure}
* and {@code onComplete} will be invoked regardless of whether this is set.
*/
public Builder setDownloadMonitor(SingleFileDownloadProgressMonitor downloadMonitor) {
this.downloadMonitorOptional = Optional.of(downloadMonitor);
return this;
}
/**
* Set the Foreground Download Service. This foreground service will keep the download alive
* even if the user navigates away from the host app. This ensures long download can finish.
*
* <p>This is required to use {@link Downloader#downloadWithForegroundService}. Not providing
* this will result in a failed future when calling downloadWithForegroundService.
*/
public Builder setForegroundDownloadService(Class<?> foregroundDownloadServiceClass) {
this.foregroundDownloadServiceClassOptional = Optional.of(foregroundDownloadServiceClass);
return this;
}
/**
* Set the FileDownloader Supplier. MDDLite takes in a Supplier of FileDownload to support lazy
* instantiation of the FileDownloader
*/
public Builder setFileDownloaderSupplier(Supplier<FileDownloader> fileDownloaderSupplier) {
this.fileDownloaderSupplier = fileDownloaderSupplier;
return this;
}
Builder() {}
public Downloader build() {
return new DownloaderImpl(
context,
foregroundDownloadServiceClassOptional,
sequentialControlExecutor,
downloadMonitorOptional,
fileDownloaderSupplier);
}
}
}