@Override
 public synchronized void shuffle() {
   Collections.shuffle(downloadList);
   if (currentPlaying != null) {
     downloadList.remove(getCurrentPlayingIndex());
     downloadList.add(0, currentPlaying);
   }
   revision++;
   lifecycleSupport.serializeDownloadQueue();
   updateJukeboxPlaylist();
 }
 @Override
 public synchronized void clearIncomplete() {
   reset();
   Iterator<DownloadFile> iterator = downloadList.iterator();
   while (iterator.hasNext()) {
     DownloadFile downloadFile = iterator.next();
     if (!downloadFile.isCompleteFileAvailable()) {
       iterator.remove();
     }
   }
   lifecycleSupport.serializeDownloadQueue();
   updateJukeboxPlaylist();
 }
 @Override
 public synchronized void remove(DownloadFile downloadFile) {
   if (downloadFile == currentDownloading) {
     currentDownloading.cancelDownload();
     currentDownloading = null;
   }
   if (downloadFile == currentPlaying) {
     reset();
     setCurrentPlaying(null);
   }
   downloadList.remove(downloadFile);
   revision++;
   lifecycleSupport.serializeDownloadQueue();
   updateJukeboxPlaylist();
 }
  public synchronized void clear(boolean serialize) {
    reset();
    downloadList.clear();
    revision++;
    if (currentDownloading != null) {
      currentDownloading.cancelDownload();
      currentDownloading = null;
    }
    setCurrentPlaying(null);

    if (serialize) {
      lifecycleSupport.serializeDownloadQueue();
    }
    updateJukeboxPlaylist();
  }
  @Override
  public synchronized void download(
      List<MusicDirectory.Entry> songs, boolean save, boolean autoplay, boolean playNext) {
    shufflePlay = false;
    int offset = 1;

    if (songs.isEmpty()) {
      return;
    }

    if (save) {
      for (MusicDirectory.Entry song : songs) {
        DownloadFile downloadFile = forSong(song);
        downloadFile.pin();
        if (!downloadFile.isWorkDone() && !downloadList.contains(downloadFile)) {
          downloadList.add(downloadFile);
        }
      }
    } else if (playNext) {
      if (autoplay && getCurrentPlayingIndex() >= 0) {
        offset = 0;
      }
      for (MusicDirectory.Entry song : songs) {
        DownloadFile downloadFile = new DownloadFile(this, song);
        downloadList.add(getCurrentPlayingIndex() + offset, downloadFile);
        offset++;
      }

    } else {
      for (MusicDirectory.Entry song : songs) {
        DownloadFile downloadFile = new DownloadFile(this, song);
        downloadList.add(downloadFile);
      }
    }

    revision++;
    updateJukeboxPlaylist();

    if (autoplay) {
      play(0);
    } else {
      if (currentPlaying == null) {
        currentPlaying = downloadList.get(0);
      }
      checkDownloads();
    }
    lifecycleSupport.serializeDownloadQueue();
  }
  private synchronized void checkShufflePlay() {

    final int listSize = 20;
    boolean wasEmpty = downloadList.isEmpty();

    long revisionBefore = revision;

    // First, ensure that list is at least 20 songs long.
    int size = size();
    if (size < listSize) {
      for (MusicDirectory.Entry song : shufflePlayBuffer.get(listSize - size)) {
        DownloadFile downloadFile = new DownloadFile(this, song);
        downloadList.add(downloadFile);
        revision++;
      }
    }

    int currIndex = currentPlaying == null ? 0 : getCurrentPlayingIndex();

    // Only shift playlist if playing song #5 or later.
    if (currIndex > 4) {
      int songsToShift = currIndex - 2;
      for (MusicDirectory.Entry song : shufflePlayBuffer.get(songsToShift)) {
        downloadList.add(new DownloadFile(this, song));
        downloadList.get(0).cancelDownload();
        downloadList.remove(0);
        revision++;
      }
    }

    if (revisionBefore != revision) {
      updateJukeboxPlaylist();
    }

    if (wasEmpty && !downloadList.isEmpty()) {
      play(0);
    }
  }