content: package de.danoeh.antennapod.net.download.service.feed;
  
  import android.content.Context;
  import androidx.work.Constraints;
  import androidx.work.Data;
  import androidx.work.ExistingWorkPolicy;
  import androidx.work.NetworkType;
  import androidx.work.OneTimeWorkRequest;
  import androidx.work.OutOfQuotaPolicy;
  import androidx.work.WorkInfo;
  import androidx.work.WorkManager;
  import de.danoeh.antennapod.net.download.service.episode.EpisodeDownloadWorker;
  import de.danoeh.antennapod.storage.database.DBWriter;
  import de.danoeh.antennapod.model.feed.FeedItem;
  import de.danoeh.antennapod.model.feed.FeedMedia;
  import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
  import de.danoeh.antennapod.storage.preferences.UserPreferences;
  import io.reactivex.rxjava3.core.Observable;
  import io.reactivex.rxjava3.schedulers.Schedulers;
  
  import java.util.List;
  import java.util.concurrent.ExecutionException;
  import java.util.concurrent.Future;
  import java.util.concurrent.TimeUnit;
  
  public class DownloadServiceInterfaceImpl extends DownloadServiceInterface {
      public void downloadNow(Context context, FeedItem item, boolean ignoreConstraints) {
          OneTimeWorkRequest.Builder workRequest = getRequest(context, item);
          workRequest.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST);
          if (ignoreConstraints) {
              workRequest.setConstraints(new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build());
          } else {
              workRequest.setConstraints(getConstraints());
          }
          WorkManager.getInstance(context).enqueueUniqueWork(item.getMedia().getDownloadUrl(),
                  ExistingWorkPolicy.KEEP, workRequest.build());
      }
  
      public void download(Context context, FeedItem item) {
          if (item.isDownloaded()) {
              return;
          }
          OneTimeWorkRequest.Builder workRequest = getRequest(context, item);
          workRequest.setConstraints(getConstraints());
          WorkManager.getInstance(context).enqueueUniqueWork(item.getMedia().getDownloadUrl(),
                  ExistingWorkPolicy.KEEP, workRequest.build());
      }
  
      private static OneTimeWorkRequest.Builder getRequest(Context context, FeedItem item) {
          OneTimeWorkRequest.Builder workRequest = new OneTimeWorkRequest.Builder(EpisodeDownloadWorker.class)
                  .setInitialDelay(0L, TimeUnit.MILLISECONDS)
                  .addTag(DownloadServiceInterface.WORK_TAG)
                  .addTag(DownloadServiceInterface.WORK_TAG_EPISODE_URL + item.getMedia().getDownloadUrl());
          if (!item.isTagged(FeedItem.TAG_QUEUE) && UserPreferences.enqueueDownloadedEpisodes()) {
              DBWriter.addQueueItem(context, item);
              workRequest.addTag(DownloadServiceInterface.WORK_DATA_WAS_QUEUED);
          }
          workRequest.setInputData(new Data.Builder().putLong(WORK_DATA_MEDIA_ID, item.getMedia().getId()).build());
          return workRequest;
      }
  
      private static Constraints getConstraints() {
          Constraints.Builder constraints = new Constraints.Builder();
          if (UserPreferences.isAllowMobileEpisodeDownload()) {
              constraints.setRequiredNetworkType(NetworkType.CONNECTED);
          } else {
              constraints.setRequiredNetworkType(NetworkType.UNMETERED);
          }
          return constraints.build();
      }
  
      @Override
      public void cancel(Context context, FeedMedia media) {
          // This needs to be done here, not in the worker. Reason: The worker might or might not be running.
          if (media.fileExists()) {
              DBWriter.deleteFeedMediaOfItem(context, media); // Remove partially downloaded file
          }
          String tag = WORK_TAG_EPISODE_URL + media.getDownloadUrl();
          Future<List<WorkInfo>> future = WorkManager.getInstance(context).getWorkInfosByTag(tag);
          Observable.fromFuture(future)
                  .subscribeOn(Schedulers.io())
                  .observeOn(Schedulers.io())
                  .subscribe(
                      workInfos -> {
                          for (WorkInfo info : workInfos) {
                              if (info.getTags().contains(DownloadServiceInterface.WORK_DATA_WAS_QUEUED)) {
                                  DBWriter.removeQueueItem(context, false, media.getItem());
                              }
                          }
                          WorkManager.getInstance(context).cancelAllWorkByTag(tag);
                      }, exception -> {
                          WorkManager.getInstance(context).cancelAllWorkByTag(tag);
                          exception.printStackTrace();
                      });
      }
  
      @Override
      public void cancelAll(Context context) {
          WorkManager.getInstance(context).cancelAllWorkByTag(WORK_TAG);
      }
  
      @Override
      public int getNumberOfActiveDownloads(Context context) {
          try {
              List<WorkInfo> workInfos = WorkManager.getInstance(context)
                      .getWorkInfosByTag(DownloadServiceInterface.WORK_TAG).get();
              int count = 0;
              for (WorkInfo info : workInfos) {
                  if (info.getState() == WorkInfo.State.RUNNING
                          || info.getState() == WorkInfo.State.ENQUEUED
                          || info.getState() == WorkInfo.State.BLOCKED) {
                      count++;
                  }
              }
              return count;
          } catch (ExecutionException | InterruptedException e) {
              return 0;
          }
      }
  }
  