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.lite; 17 18 import android.content.Context; 19 import com.google.android.libraries.mobiledatadownload.downloader.FileDownloader; 20 import com.google.common.base.Optional; 21 import com.google.common.base.Preconditions; 22 import com.google.common.base.Supplier; 23 import com.google.common.util.concurrent.ListenableFuture; 24 import com.google.common.util.concurrent.MoreExecutors; 25 import com.google.errorprone.annotations.CanIgnoreReturnValue; 26 import com.google.errorprone.annotations.CheckReturnValue; 27 import java.util.concurrent.Executor; 28 29 /** The root object and entry point for the MDDLite (<internal>). */ 30 public interface Downloader { 31 32 /** 33 * Downloads a file with the given {@link DownloadRequest}. 34 * 35 * <p>This method will not create a notification and will not run in a ForegroundService. 36 * 37 * <p>NOTE: The caller is responsible for keeping the download alive. This is typically used by 38 * clients who use a service the platform binds with, so a notification is not needed. If you are 39 * unsure whether to use this method or {@link #downloadWithForegroundService}, contact the MDD 40 * team (<internal>@ or via <a href="<internal>">yaqs</a>. 41 */ 42 @CheckReturnValue download(DownloadRequest downloadRequest)43 ListenableFuture<Void> download(DownloadRequest downloadRequest); 44 45 /** 46 * Download a file and show foreground download progress in a notification. User can cancel the 47 * download from the notification menu. 48 * 49 * <p>NOTE: Calling downloadWithForegroundService without a provided ForegroundService will return 50 * a failed future. 51 * 52 * <p>The cancel action in the notification menu requires the ForegroundService to be registered 53 * with the application (via the AndroidManifest.xml). This allows the cancellation intents to be 54 * properly picked up. To register the service, the following lines must be included in the app's 55 * {@code AndroidManifest.xml}: 56 * 57 * <pre>{@code 58 * <!-- Needed by foreground download service --> 59 * <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> 60 * 61 * <!-- Service for MDD Lite foreground downloads --> 62 * <service 63 * android:name="com.google.android.libraries.mobiledatadownload.lite.sting.ForegroundDownloadService" 64 * android:exported="false" /> 65 * }</pre> 66 * 67 * <p>NOTE: The above excerpt is for Framework and Sting apps. Dagger apps should use the same 68 * excerpt, but change the {@code android:name} property to: 69 * 70 * <pre>{@code 71 * android:name="com.google.android.libraries.mobiledatadownload.lite.dagger.ForegroundDownloadService" 72 * }</pre> 73 */ 74 @CheckReturnValue downloadWithForegroundService(DownloadRequest downloadRequest)75 ListenableFuture<Void> downloadWithForegroundService(DownloadRequest downloadRequest); 76 77 /** 78 * Cancel an on-going foreground download. 79 * 80 * <p>Use {@link ForegroundDownloadKey} to construct the unique key. 81 * 82 * <p><b>NOTE:</b> In most cases, clients will not need to call this -- it is meant to allow the 83 * ForegroundDownloadService to cancel a download via the Cancel action registered to a 84 * notification. 85 * 86 * <p>Clients should prefer to cancel the future returned to them from {@link 87 * #downloadWithForegroundService} instead. 88 */ cancelForegroundDownload(String downloadKey)89 void cancelForegroundDownload(String downloadKey); 90 newBuilder()91 static Downloader.Builder newBuilder() { 92 return new Downloader.Builder(); 93 } 94 95 /** A Builder for the {@link Downloader}. */ 96 final class Builder { 97 98 private static final String TAG = "Builder"; 99 private Executor sequentialControlExecutor; 100 101 private Context context; 102 private Supplier<FileDownloader> fileDownloaderSupplier; 103 private Optional<SingleFileDownloadProgressMonitor> downloadMonitorOptional = Optional.absent(); 104 private Optional<Class<?>> foregroundDownloadServiceClassOptional = Optional.absent(); 105 106 @CanIgnoreReturnValue setContext(Context context)107 public Builder setContext(Context context) { 108 this.context = context.getApplicationContext(); 109 return this; 110 } 111 112 /** Set the Control Executor which will run MDDLite control flow. */ 113 @CanIgnoreReturnValue setControlExecutor(Executor controlExecutor)114 public Builder setControlExecutor(Executor controlExecutor) { 115 Preconditions.checkNotNull(controlExecutor); 116 // Executor that will execute tasks sequentially. 117 this.sequentialControlExecutor = MoreExecutors.newSequentialExecutor(controlExecutor); 118 return this; 119 } 120 121 /** 122 * Set the SingleFileDownloadProgressMonitor. This instance must be the same instance that is 123 * registered with SynchronousFileStorage. 124 * 125 * <p>This is required to use {@link Downloader#downloadWithForegroundService}. Not providing 126 * this will result in a failed future when calling downloadWithForegroundService. 127 * 128 * <p>This is required to track progress updates and network pauses when passing a {@link 129 * DownloadListener} to {@link Downloader#download}. The DownloadListener's {@code onFailure} 130 * and {@code onComplete} will be invoked regardless of whether this is set. 131 */ 132 @CanIgnoreReturnValue setDownloadMonitor(SingleFileDownloadProgressMonitor downloadMonitor)133 public Builder setDownloadMonitor(SingleFileDownloadProgressMonitor downloadMonitor) { 134 this.downloadMonitorOptional = Optional.of(downloadMonitor); 135 return this; 136 } 137 138 /** 139 * Set the Foreground Download Service. This foreground service will keep the download alive 140 * even if the user navigates away from the host app. This ensures long download can finish. 141 * 142 * <p>This is required to use {@link Downloader#downloadWithForegroundService}. Not providing 143 * this will result in a failed future when calling downloadWithForegroundService. 144 */ 145 @CanIgnoreReturnValue setForegroundDownloadService(Class<?> foregroundDownloadServiceClass)146 public Builder setForegroundDownloadService(Class<?> foregroundDownloadServiceClass) { 147 this.foregroundDownloadServiceClassOptional = Optional.of(foregroundDownloadServiceClass); 148 return this; 149 } 150 151 /** 152 * Set the FileDownloader Supplier. MDDLite takes in a Supplier of FileDownload to support lazy 153 * instantiation of the FileDownloader 154 */ 155 @CanIgnoreReturnValue setFileDownloaderSupplier(Supplier<FileDownloader> fileDownloaderSupplier)156 public Builder setFileDownloaderSupplier(Supplier<FileDownloader> fileDownloaderSupplier) { 157 this.fileDownloaderSupplier = fileDownloaderSupplier; 158 return this; 159 } 160 Builder()161 Builder() {} 162 build()163 public Downloader build() { 164 return new DownloaderImpl( 165 context, 166 foregroundDownloadServiceClassOptional, 167 sequentialControlExecutor, 168 downloadMonitorOptional, 169 fileDownloaderSupplier); 170 } 171 } 172 } 173