Refactored playback related things

This commit is contained in:
Nite 2020-06-23 18:40:44 +02:00
parent 53628dde54
commit 0820763c7f
No known key found for this signature in database
GPG Key ID: 1D1AD59B1C6386C1
20 changed files with 1903 additions and 1726 deletions

View File

@ -310,7 +310,7 @@ public class BookmarkActivity extends SubsonicTabActivity
for (MusicDirectory.Entry song : selection) for (MusicDirectory.Entry song : selection)
{ {
DownloadFile downloadFile = getDownloadService().forSong(song); DownloadFile downloadFile = downloader.getValue().getDownloadFileForSong(song);
if (downloadFile.isWorkDone()) if (downloadFile.isWorkDone())
{ {
deleteEnabled = true; deleteEnabled = true;

View File

@ -293,7 +293,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
@Override @Override
protected Boolean doInBackground() throws Throwable protected Boolean doInBackground() throws Throwable
{ {
if (getDownloadService().getCurrentPlayingIndex() < getDownloadService().size() - 1) if (downloader.getValue().getCurrentPlayingIndex() < downloader.getValue().downloadList.size() - 1)
{ {
getDownloadService().next(); getDownloadService().next();
return true; return true;
@ -567,7 +567,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
final DownloadService downloadService = getDownloadService(); final DownloadService downloadService = getDownloadService();
if (downloadService == null || downloadService.getCurrentPlaying() == null) if (downloadService == null || player.getValue().currentPlaying == null)
{ {
playlistFlipper.setDisplayedChild(1); playlistFlipper.setDisplayedChild(1);
} }
@ -632,7 +632,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
} }
} }
final DownloadFile currentDownloading = getDownloadService().getCurrentDownloading(); final DownloadFile currentDownloading = downloader.getValue().currentDownloading;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
if (currentDownloading == playlistView.getItemAtPosition(i)) if (currentDownloading == playlistView.getItemAtPosition(i))
@ -782,7 +782,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
if (downloadService != null) if (downloadService != null)
{ {
DownloadFile downloadFile = downloadService.getCurrentPlaying(); DownloadFile downloadFile = player.getValue().currentPlaying;
if (downloadFile != null) if (downloadFile != null)
{ {
@ -1019,7 +1019,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
onDownloadListChanged(); onDownloadListChanged();
return true; return true;
case R.id.menu_item_save_playlist: case R.id.menu_item_save_playlist:
if (!getDownloadService().getSongs().isEmpty()) if (!downloader.getValue().downloadList.isEmpty())
{ {
showDialog(DIALOG_SAVE_PLAYLIST); showDialog(DIALOG_SAVE_PLAYLIST);
} }
@ -1142,7 +1142,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
if (downloadService != null) if (downloadService != null)
{ {
List<DownloadFile> downloadServiceSongs = downloadService.getSongs(); List<DownloadFile> downloadServiceSongs = downloader.getValue().downloadList;
if (downloadServiceSongs != null) if (downloadServiceSongs != null)
{ {
@ -1175,12 +1175,12 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
return; return;
} }
if (currentRevision != getDownloadService().getDownloadListUpdateRevision()) if (currentRevision != downloader.getValue().getDownloadListUpdateRevision())
{ {
onDownloadListChanged(); onDownloadListChanged();
} }
if (currentPlaying != getDownloadService().getCurrentPlaying()) if (currentPlaying != player.getValue().currentPlaying)
{ {
onCurrentChanged(); onCurrentChanged();
} }
@ -1199,7 +1199,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
protected Void doInBackground() throws Throwable protected Void doInBackground() throws Throwable
{ {
final List<MusicDirectory.Entry> entries = new LinkedList<MusicDirectory.Entry>(); final List<MusicDirectory.Entry> entries = new LinkedList<MusicDirectory.Entry>();
for (final DownloadFile downloadFile : getDownloadService().getSongs()) for (final DownloadFile downloadFile : downloader.getValue().downloadList)
{ {
entries.add(downloadFile.getSong()); entries.add(downloadFile.getSong());
} }
@ -1254,7 +1254,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
{ {
warnIfNetworkOrStorageUnavailable(); warnIfNetworkOrStorageUnavailable();
final int current = service.getCurrentPlayingIndex(); final int current = downloader.getValue().getCurrentPlayingIndex();
if (current == -1) if (current == -1)
{ {
@ -1275,7 +1275,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
return; return;
} }
final List<DownloadFile> list = downloadService.getSongs(); final List<DownloadFile> list = downloader.getValue().downloadList;
emptyTextView.setText(R.string.download_empty); emptyTextView.setText(R.string.download_empty);
final SongListAdapter adapter = new SongListAdapter(this, list); final SongListAdapter adapter = new SongListAdapter(this, list);
@ -1313,7 +1313,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
return; return;
} }
DownloadFile currentPlaying = downloadService.getCurrentPlaying(); DownloadFile currentPlaying = player.getValue().currentPlaying;
if (currentPlaying == item) if (currentPlaying == item)
{ {
@ -1333,7 +1333,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
}); });
emptyTextView.setVisibility(list.isEmpty() ? View.VISIBLE : View.GONE); emptyTextView.setVisibility(list.isEmpty() ? View.VISIBLE : View.GONE);
currentRevision = downloadService.getDownloadListUpdateRevision(); currentRevision = downloader.getValue().getDownloadListUpdateRevision();
switch (downloadService.getRepeatMode()) switch (downloadService.getRepeatMode())
{ {
@ -1360,13 +1360,13 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
return; return;
} }
currentPlaying = downloadService.getCurrentPlaying(); currentPlaying = player.getValue().currentPlaying;
scrollToCurrent(); scrollToCurrent();
long totalDuration = downloadService.getDownloadListDuration(); long totalDuration = downloader.getValue().getDownloadListDuration();
long totalSongs = downloadService.getSongs().size(); long totalSongs = downloader.getValue().downloadList.size();
int currentSongIndex = downloadService.getCurrentPlayingIndex() + 1; int currentSongIndex = downloader.getValue().getCurrentPlayingIndex() + 1;
String duration = Util.formatTotalDuration(totalDuration); String duration = Util.formatTotalDuration(totalDuration);
@ -1580,7 +1580,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi
if (e1X - e2X > swipeDistance && absX > swipeVelocity) if (e1X - e2X > swipeDistance && absX > swipeVelocity)
{ {
warnIfNetworkOrStorageUnavailable(); warnIfNetworkOrStorageUnavailable();
if (downloadService.getCurrentPlayingIndex() < downloadService.size() - 1) if (downloader.getValue().getCurrentPlayingIndex() < downloader.getValue().downloadList.size() - 1)
{ {
downloadService.next(); downloadService.next();
onCurrentChanged(); onCurrentChanged();

View File

@ -520,7 +520,7 @@ public class SearchActivity extends SubsonicTabActivity
if (autoplay) if (autoplay)
{ {
downloadService.play(downloadService.size() - 1); downloadService.play(downloader.getValue().downloadList.size() - 1);
} }
Util.toast(SearchActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_added, 1, 1)); Util.toast(SearchActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_added, 1, 1));

View File

@ -1024,7 +1024,7 @@ public class SelectAlbumActivity extends SubsonicTabActivity
for (MusicDirectory.Entry song : selection) for (MusicDirectory.Entry song : selection)
{ {
DownloadFile downloadFile = getDownloadService().forSong(song); DownloadFile downloadFile = downloader.getValue().getDownloadFileForSong(song);
if (downloadFile.isWorkDone()) if (downloadFile.isWorkDone())
{ {
deleteEnabled = true; deleteEnabled = true;

View File

@ -78,6 +78,9 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen
private Lazy<DownloadServiceImpl> downloadServiceImpl = inject(DownloadServiceImpl.class); private Lazy<DownloadServiceImpl> downloadServiceImpl = inject(DownloadServiceImpl.class);
private Lazy<DownloadServiceLifecycleSupport> lifecycleSupport = inject(DownloadServiceLifecycleSupport.class); private Lazy<DownloadServiceLifecycleSupport> lifecycleSupport = inject(DownloadServiceLifecycleSupport.class);
protected Lazy<Downloader> downloader = inject(Downloader.class);
protected Lazy<Player> player = inject(Player.class);
public MenuDrawer menuDrawer; public MenuDrawer menuDrawer;
private int activePosition = 1; private int activePosition = 1;
@ -266,7 +269,7 @@ public class SubsonicTabActivity extends ResultActivity implements OnClickListen
if (playerState.equals(PlayerState.PAUSED) || playerState.equals(PlayerState.STARTED)) if (playerState.equals(PlayerState.PAUSED) || playerState.equals(PlayerState.STARTED))
{ {
DownloadFile file = downloadServiceImpl.getValue().getCurrentPlaying(); DownloadFile file = player.getValue().currentPlaying;
if (file != null) if (file != null)
{ {

View File

@ -5,8 +5,9 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import org.moire.ultrasonic.domain.MusicDirectory.Entry; import org.moire.ultrasonic.domain.MusicDirectory.Entry;
import org.moire.ultrasonic.service.DownloadService;
import org.moire.ultrasonic.service.DownloadServiceImpl; import org.moire.ultrasonic.service.DownloadServiceImpl;
import org.moire.ultrasonic.service.Downloader;
import org.moire.ultrasonic.service.Player;
import kotlin.Lazy; import kotlin.Lazy;
@ -16,16 +17,18 @@ public class A2dpIntentReceiver extends BroadcastReceiver
{ {
private static final String PLAYSTATUS_RESPONSE = "com.android.music.playstatusresponse"; private static final String PLAYSTATUS_RESPONSE = "com.android.music.playstatusresponse";
private Lazy<DownloadServiceImpl> downloadServiceImpl = inject(DownloadServiceImpl.class); private Lazy<DownloadServiceImpl> downloadServiceImpl = inject(DownloadServiceImpl.class);
private Lazy<Downloader> downloader = inject(Downloader.class);
protected Lazy<Player> player = inject(Player.class);
@Override @Override
public void onReceive(Context context, Intent intent) public void onReceive(Context context, Intent intent)
{ {
if (downloadServiceImpl.getValue().getCurrentPlaying() == null) if (player.getValue().currentPlaying == null)
{ {
return; return;
} }
Entry song = downloadServiceImpl.getValue().getCurrentPlaying().getSong(); Entry song = player.getValue().currentPlaying.getSong();
if (song == null) if (song == null)
{ {
@ -35,8 +38,8 @@ public class A2dpIntentReceiver extends BroadcastReceiver
Intent avrcpIntent = new Intent(PLAYSTATUS_RESPONSE); Intent avrcpIntent = new Intent(PLAYSTATUS_RESPONSE);
Integer duration = song.getDuration(); Integer duration = song.getDuration();
Integer playerPosition = downloadServiceImpl.getValue().getPlayerPosition(); int playerPosition = downloadServiceImpl.getValue().getPlayerPosition();
Integer listSize = downloadServiceImpl.getValue().getDownloads().size(); int listSize = downloader.getValue().getDownloads().size();
if (duration != null) if (duration != null)
{ {
@ -52,11 +55,7 @@ public class A2dpIntentReceiver extends BroadcastReceiver
avrcpIntent.putExtra("playing", true); avrcpIntent.putExtra("playing", true);
break; break;
case STOPPED: case STOPPED:
avrcpIntent.putExtra("playing", false);
break;
case PAUSED: case PAUSED:
avrcpIntent.putExtra("playing", false);
break;
case COMPLETED: case COMPLETED:
avrcpIntent.putExtra("playing", false); avrcpIntent.putExtra("playing", false);
break; break;

View File

@ -0,0 +1,6 @@
package org.moire.ultrasonic.service;
public abstract class BiConsumer<T, U>
{
public abstract void accept(T t, U u);
}

View File

@ -68,6 +68,9 @@ public class DownloadFile
private volatile boolean saveWhenDone; private volatile boolean saveWhenDone;
private volatile boolean completeWhenDone; private volatile boolean completeWhenDone;
private Lazy<Downloader> downloader = inject(Downloader.class);
public DownloadFile(Context context, MusicDirectory.Entry song, boolean save) public DownloadFile(Context context, MusicDirectory.Entry song, boolean save)
{ {
super(); super();
@ -443,7 +446,7 @@ public class DownloadFile
new CacheCleaner(context).cleanSpace(); new CacheCleaner(context).cleanSpace();
MediaPlayerService.checkDownloads(context); downloader.getValue().checkDownloads();
} }
} }

View File

@ -61,30 +61,10 @@ public interface DownloadService
void clear(); void clear();
void clearBackground();
void clearIncomplete(); void clearIncomplete();
int size();
void remove(int which);
void remove(DownloadFile downloadFile); void remove(DownloadFile downloadFile);
long getDownloadListDuration();
List<DownloadFile> getSongs();
List<DownloadFile> getDownloads();
List<DownloadFile> getBackgroundDownloads();
int getCurrentPlayingIndex();
DownloadFile getCurrentPlaying();
DownloadFile getCurrentDownloading();
void play(int index); void play(int index);
void seekTo(int position); void seekTo(int position);
@ -111,10 +91,6 @@ public interface DownloadService
void unpin(List<Entry> songs); void unpin(List<Entry> songs);
DownloadFile forSong(Entry song);
long getDownloadListUpdateRevision();
void setSuggestedPlaylistName(String name); void setSuggestedPlaylistName(String name);
String getSuggestedPlaylistName(); String getSuggestedPlaylistName();

View File

@ -32,19 +32,15 @@ import org.moire.ultrasonic.domain.RepeatMode;
import org.moire.ultrasonic.domain.UserInfo; import org.moire.ultrasonic.domain.UserInfo;
import org.moire.ultrasonic.featureflags.Feature; import org.moire.ultrasonic.featureflags.Feature;
import org.moire.ultrasonic.featureflags.FeatureStorage; import org.moire.ultrasonic.featureflags.FeatureStorage;
import org.moire.ultrasonic.util.LRUCache;
import org.moire.ultrasonic.util.ShufflePlayBuffer; import org.moire.ultrasonic.util.ShufflePlayBuffer;
import org.moire.ultrasonic.util.Util; import org.moire.ultrasonic.util.Util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import kotlin.Lazy; import kotlin.Lazy;
import static org.koin.java.standalone.KoinJavaComponent.inject; import static org.koin.java.standalone.KoinJavaComponent.inject;
import static org.moire.ultrasonic.service.MediaPlayerService.playerState;
/** /**
* @author Sindre Mehus, Joshua Bahnsen * @author Sindre Mehus, Joshua Bahnsen
@ -54,8 +50,6 @@ public class DownloadServiceImpl implements DownloadService
{ {
private static final String TAG = DownloadServiceImpl.class.getSimpleName(); private static final String TAG = DownloadServiceImpl.class.getSimpleName();
private final LRUCache<MusicDirectory.Entry, DownloadFile> downloadFileCache = new LRUCache<>(100);
private String suggestedPlaylistName; private String suggestedPlaylistName;
private boolean keepScreenOn; private boolean keepScreenOn;
@ -66,13 +60,18 @@ public class DownloadServiceImpl implements DownloadService
public Lazy<JukeboxService> jukeboxService = inject(JukeboxService.class); public Lazy<JukeboxService> jukeboxService = inject(JukeboxService.class);
private Lazy<DownloadQueueSerializer> downloadQueueSerializer = inject(DownloadQueueSerializer.class); private Lazy<DownloadQueueSerializer> downloadQueueSerializer = inject(DownloadQueueSerializer.class);
private Lazy<ExternalStorageMonitor> externalStorageMonitor = inject(ExternalStorageMonitor.class); private Lazy<ExternalStorageMonitor> externalStorageMonitor = inject(ExternalStorageMonitor.class);
private final Downloader downloader;
private final ShufflePlayBuffer shufflePlayBuffer;
private final Player player;
public DownloadServiceImpl(Context context) public DownloadServiceImpl(Context context, Downloader downloader, ShufflePlayBuffer shufflePlayBuffer,
Player player)
{ {
this.context = context; this.context = context;
this.downloader = downloader;
this.shufflePlayBuffer = shufflePlayBuffer;
this.player = player;
// TODO: refactor
MediaPlayerService.shufflePlayBuffer = new ShufflePlayBuffer(context);
externalStorageMonitor.getValue().onCreate(new Runnable() { externalStorageMonitor.getValue().onCreate(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -120,26 +119,25 @@ public class DownloadServiceImpl implements DownloadService
} }
}); });
if (MediaPlayerService.currentPlaying != null) if (player.currentPlaying != null)
{ {
if (autoPlay && jukeboxService.getValue().isEnabled()) if (autoPlay && jukeboxService.getValue().isEnabled())
{ {
jukeboxService.getValue().skip(getCurrentPlayingIndex(), currentPlayingPosition / 1000); jukeboxService.getValue().skip(downloader.getCurrentPlayingIndex(), currentPlayingPosition / 1000);
} }
else else
{ {
if (MediaPlayerService.currentPlaying.isCompleteFileAvailable()) if (player.currentPlaying.isCompleteFileAvailable())
{ {
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() { executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() {
@Override @Override
public void accept(MediaPlayerService mediaPlayerService) { public void accept(MediaPlayerService mediaPlayerService) {
mediaPlayerService.doPlay(MediaPlayerService.currentPlaying, currentPlayingPosition, autoPlay); player.doPlay(player.currentPlaying, currentPlayingPosition, autoPlay);
} }
}); });
} }
} }
} }
autoPlayStart = false; autoPlayStart = false;
} }
} }
@ -168,7 +166,7 @@ public class DownloadServiceImpl implements DownloadService
@Override @Override
public synchronized void togglePlayPause() public synchronized void togglePlayPause()
{ {
if (playerState == PlayerState.IDLE) autoPlayStart = true; if (player.playerState == PlayerState.IDLE) autoPlayStart = true;
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() { executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() {
@Override @Override
public void accept(MediaPlayerService mediaPlayerService) { public void accept(MediaPlayerService mediaPlayerService) {
@ -222,96 +220,42 @@ public class DownloadServiceImpl implements DownloadService
} }
@Override @Override
public synchronized void download(List<MusicDirectory.Entry> songs, boolean save, boolean autoplay, boolean playNext, boolean shuffle, boolean newPlaylist) public synchronized void download(List<MusicDirectory.Entry> songs, boolean save, boolean autoPlay, boolean playNext, boolean shuffle, boolean newPlaylist)
{ {
MediaPlayerService.shufflePlay = false; downloader.download(songs, save, autoPlay, playNext, newPlaylist);
int offset = 1; jukeboxService.getValue().updatePlaylist();
if (songs.isEmpty()) if (shuffle) shuffle();
{
return;
}
if (newPlaylist) if (!playNext && !autoPlay && (downloader.downloadList.size() - 1) == downloader.getCurrentPlayingIndex())
{
MediaPlayerService.downloadList.clear();
}
if (playNext)
{
if (autoplay && getCurrentPlayingIndex() >= 0)
{
offset = 0;
}
for (MusicDirectory.Entry song : songs)
{
DownloadFile downloadFile = new DownloadFile(context, song, save);
MediaPlayerService.downloadList.add(getCurrentPlayingIndex() + offset, downloadFile);
offset++;
}
}
else
{
int size = size();
int index = getCurrentPlayingIndex();
for (MusicDirectory.Entry song : songs)
{
DownloadFile downloadFile = new DownloadFile(context, song, save);
MediaPlayerService.downloadList.add(downloadFile);
}
if (!autoplay && (size - 1) == index)
{ {
MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
if (mediaPlayerService != null) mediaPlayerService.setNextPlaying(); if (mediaPlayerService != null) mediaPlayerService.setNextPlaying();
} }
} if (autoPlay)
MediaPlayerService.revision++;
jukeboxService.getValue().updatePlaylist();
if (shuffle) shuffle();
if (autoplay)
{ {
play(0); play(0);
} }
else else
{ {
if (MediaPlayerService.currentPlaying == null) downloader.setFirstPlaying();
{
MediaPlayerService.currentPlaying = MediaPlayerService.downloadList.get(0);
MediaPlayerService.currentPlaying.setPlaying(true);
} }
MediaPlayerService.checkDownloads(context); downloadQueueSerializer.getValue().serializeDownloadQueue(downloader.downloadList, downloader.getCurrentPlayingIndex(), getPlayerPosition());
}
downloadQueueSerializer.getValue().serializeDownloadQueue(getSongs(), getCurrentPlayingIndex(), getPlayerPosition());
} }
@Override @Override
public synchronized void downloadBackground(List<MusicDirectory.Entry> songs, boolean save) public synchronized void downloadBackground(List<MusicDirectory.Entry> songs, boolean save)
{ {
for (MusicDirectory.Entry song : songs) downloader.downloadBackground(songs, save);
{ downloadQueueSerializer.getValue().serializeDownloadQueue(downloader.downloadList, downloader.getCurrentPlayingIndex(), getPlayerPosition());
DownloadFile downloadFile = new DownloadFile(context, song, save);
MediaPlayerService.backgroundDownloadList.add(downloadFile);
}
MediaPlayerService.revision++;
MediaPlayerService.checkDownloads(context);
downloadQueueSerializer.getValue().serializeDownloadQueue(getSongs(), getCurrentPlayingIndex(), getPlayerPosition());
} }
public synchronized void setCurrentPlaying(DownloadFile currentPlaying) public synchronized void setCurrentPlaying(DownloadFile currentPlaying)
{ {
MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
if (mediaPlayerService != null) mediaPlayerService.setCurrentPlaying(currentPlaying); if (mediaPlayerService != null) player.setCurrentPlaying(currentPlaying);
} }
public synchronized void setCurrentPlaying(int index) public synchronized void setCurrentPlaying(int index)
@ -323,7 +267,7 @@ public class DownloadServiceImpl implements DownloadService
public synchronized void setPlayerState(PlayerState state) public synchronized void setPlayerState(PlayerState state)
{ {
MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
if (mediaPlayerService != null) mediaPlayerService.setPlayerState(state); if (mediaPlayerService != null) player.setPlayerState(state);
} }
@Override @Override
@ -341,31 +285,26 @@ public class DownloadServiceImpl implements DownloadService
@Override @Override
public synchronized void setShufflePlayEnabled(boolean enabled) public synchronized void setShufflePlayEnabled(boolean enabled)
{ {
MediaPlayerService.shufflePlay = enabled; shufflePlayBuffer.isEnabled = enabled;
if (MediaPlayerService.shufflePlay) if (enabled)
{ {
clear(); clear();
MediaPlayerService.checkDownloads(context); downloader.checkDownloads();
} }
} }
@Override @Override
public boolean isShufflePlayEnabled() public boolean isShufflePlayEnabled()
{ {
return MediaPlayerService.shufflePlay; return shufflePlayBuffer.isEnabled;
} }
@Override @Override
public synchronized void shuffle() public synchronized void shuffle()
{ {
Collections.shuffle(MediaPlayerService.downloadList); downloader.shuffle();
if (MediaPlayerService.currentPlaying != null)
{ downloadQueueSerializer.getValue().serializeDownloadQueue(downloader.downloadList, downloader.getCurrentPlayingIndex(), getPlayerPosition());
MediaPlayerService.downloadList.remove(getCurrentPlayingIndex());
MediaPlayerService.downloadList.add(0, MediaPlayerService.currentPlaying);
}
MediaPlayerService.revision++;
downloadQueueSerializer.getValue().serializeDownloadQueue(getSongs(), getCurrentPlayingIndex(), getPlayerPosition());
jukeboxService.getValue().updatePlaylist(); jukeboxService.getValue().updatePlaylist();
MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
@ -410,33 +349,6 @@ public class DownloadServiceImpl implements DownloadService
this.showVisualization = showVisualization; this.showVisualization = showVisualization;
} }
@Override
public synchronized DownloadFile forSong(MusicDirectory.Entry song)
{
for (DownloadFile downloadFile : MediaPlayerService.downloadList)
{
if (downloadFile.getSong().equals(song) && ((downloadFile.isDownloading() && !downloadFile.isDownloadCancelled() && downloadFile.getPartialFile().exists()) || downloadFile.isWorkDone()))
{
return downloadFile;
}
}
for (DownloadFile downloadFile : MediaPlayerService.backgroundDownloadList)
{
if (downloadFile.getSong().equals(song))
{
return downloadFile;
}
}
DownloadFile downloadFile = downloadFileCache.get(song);
if (downloadFile == null)
{
downloadFile = new DownloadFile(context, song, false);
downloadFileCache.put(song, downloadFile);
}
return downloadFile;
}
@Override @Override
public synchronized void clear() public synchronized void clear()
{ {
@ -445,30 +357,17 @@ public class DownloadServiceImpl implements DownloadService
public synchronized void clear(boolean serialize) public synchronized void clear(boolean serialize)
{ {
MediaPlayerService.clear(serialize); MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
jukeboxService.getValue().updatePlaylist(); if (mediaPlayerService != null) mediaPlayerService.clear(serialize);
if (serialize)
{
downloadQueueSerializer.getValue().serializeDownloadQueue(getSongs(), getCurrentPlayingIndex(), getPlayerPosition());
}
}
@Override jukeboxService.getValue().updatePlaylist();
public synchronized void clearBackground()
{
if (MediaPlayerService.currentDownloading != null && MediaPlayerService.backgroundDownloadList.contains(MediaPlayerService.currentDownloading))
{
MediaPlayerService.currentDownloading.cancelDownload();
MediaPlayerService.currentDownloading = null;
}
MediaPlayerService.backgroundDownloadList.clear();
} }
@Override @Override
public synchronized void clearIncomplete() public synchronized void clearIncomplete()
{ {
reset(); reset();
Iterator<DownloadFile> iterator = MediaPlayerService.downloadList.iterator(); Iterator<DownloadFile> iterator = downloader.downloadList.iterator();
while (iterator.hasNext()) while (iterator.hasNext())
{ {
@ -479,41 +378,25 @@ public class DownloadServiceImpl implements DownloadService
} }
} }
downloadQueueSerializer.getValue().serializeDownloadQueue(getSongs(), getCurrentPlayingIndex(), getPlayerPosition()); downloadQueueSerializer.getValue().serializeDownloadQueue(downloader.downloadList, downloader.getCurrentPlayingIndex(), getPlayerPosition());
jukeboxService.getValue().updatePlaylist(); jukeboxService.getValue().updatePlaylist();
} }
@Override
public synchronized int size()
{
return MediaPlayerService.downloadList.size();
}
@Override
public synchronized void remove(int which)
{
MediaPlayerService.downloadList.remove(which);
}
@Override @Override
public synchronized void remove(DownloadFile downloadFile) public synchronized void remove(DownloadFile downloadFile)
{ {
if (downloadFile == MediaPlayerService.currentDownloading) if (downloadFile == player.currentPlaying)
{
MediaPlayerService.currentDownloading.cancelDownload();
MediaPlayerService.currentDownloading = null;
}
if (downloadFile == MediaPlayerService.currentPlaying)
{ {
reset(); reset();
setCurrentPlaying(null); setCurrentPlaying(null);
} }
MediaPlayerService.downloadList.remove(downloadFile);
MediaPlayerService.backgroundDownloadList.remove(downloadFile); downloader.removeDownloadFile(downloadFile);
MediaPlayerService.revision++;
downloadQueueSerializer.getValue().serializeDownloadQueue(getSongs(), getCurrentPlayingIndex(), getPlayerPosition()); downloadQueueSerializer.getValue().serializeDownloadQueue(downloader.downloadList, downloader.getCurrentPlayingIndex(), getPlayerPosition());
jukeboxService.getValue().updatePlaylist(); jukeboxService.getValue().updatePlaylist();
if (downloadFile == MediaPlayerService.nextPlaying)
if (downloadFile == player.nextPlaying)
{ {
MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
if (mediaPlayerService != null) mediaPlayerService.setNextPlaying(); if (mediaPlayerService != null) mediaPlayerService.setNextPlaying();
@ -525,7 +408,7 @@ public class DownloadServiceImpl implements DownloadService
{ {
for (MusicDirectory.Entry song : songs) for (MusicDirectory.Entry song : songs)
{ {
forSong(song).delete(); downloader.getDownloadFileForSong(song).delete();
} }
} }
@ -534,76 +417,14 @@ public class DownloadServiceImpl implements DownloadService
{ {
for (MusicDirectory.Entry song : songs) for (MusicDirectory.Entry song : songs)
{ {
forSong(song).unpin(); downloader.getDownloadFileForSong(song).unpin();
} }
} }
@Override
public synchronized int getCurrentPlayingIndex()
{
return MediaPlayerService.downloadList.indexOf(MediaPlayerService.currentPlaying);
}
@Override
public DownloadFile getCurrentPlaying()
{
return MediaPlayerService.currentPlaying;
}
@Override
public DownloadFile getCurrentDownloading()
{
return MediaPlayerService.currentDownloading;
}
@Override
public List<DownloadFile> getSongs() { return MediaPlayerService.downloadList; }
@Override
public long getDownloadListDuration()
{
long totalDuration = 0;
for (DownloadFile downloadFile : MediaPlayerService.downloadList)
{
Entry entry = downloadFile.getSong();
if (!entry.isDirectory())
{
if (entry.getArtist() != null)
{
Integer duration = entry.getDuration();
if (duration != null)
{
totalDuration += duration;
}
}
}
}
return totalDuration;
}
@Override
public synchronized List<DownloadFile> getDownloads()
{
List<DownloadFile> temp = new ArrayList<>();
temp.addAll(MediaPlayerService.downloadList);
temp.addAll(MediaPlayerService.backgroundDownloadList);
return temp;
}
@Override
public List<DownloadFile> getBackgroundDownloads()
{
return MediaPlayerService.backgroundDownloadList;
}
@Override @Override
public synchronized void previous() public synchronized void previous()
{ {
int index = getCurrentPlayingIndex(); int index = downloader.getCurrentPlayingIndex();
if (index == -1) if (index == -1)
{ {
return; return;
@ -623,7 +444,7 @@ public class DownloadServiceImpl implements DownloadService
@Override @Override
public synchronized void next() public synchronized void next()
{ {
int index = getCurrentPlayingIndex(); int index = downloader.getCurrentPlayingIndex();
if (index != -1) if (index != -1)
{ {
play(index + 1); play(index + 1);
@ -634,7 +455,7 @@ public class DownloadServiceImpl implements DownloadService
public synchronized void reset() public synchronized void reset()
{ {
MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
if (mediaPlayerService != null) mediaPlayerService.reset(); if (mediaPlayerService != null) player.reset();
} }
@Override @Override
@ -648,24 +469,22 @@ public class DownloadServiceImpl implements DownloadService
@Override @Override
public synchronized int getPlayerDuration() public synchronized int getPlayerDuration()
{ {
if (MediaPlayerService.currentPlaying != null) if (player.currentPlaying != null)
{ {
Integer duration = MediaPlayerService.currentPlaying.getSong().getDuration(); Integer duration = player.currentPlaying.getSong().getDuration();
if (duration != null) if (duration != null)
{ {
return duration * 1000; return duration * 1000;
} }
} }
MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
if (mediaPlayerService == null) return 0; if (mediaPlayerService == null) return 0;
return mediaPlayerService.getPlayerDuration(); return mediaPlayerService.getPlayerDuration();
} }
@Override @Override
public PlayerState getPlayerState() public PlayerState getPlayerState() { return player.playerState; }
{
return playerState;
}
@Override @Override
public void setSuggestedPlaylistName(String name) public void setSuggestedPlaylistName(String name)
@ -680,12 +499,12 @@ public class DownloadServiceImpl implements DownloadService
} }
@Override @Override
public boolean getEqualizerAvailable() { return MediaPlayerService.equalizerAvailable; } public boolean getEqualizerAvailable() { return player.equalizerAvailable; }
@Override @Override
public boolean getVisualizerAvailable() public boolean getVisualizerAvailable()
{ {
return MediaPlayerService.visualizerAvailable; return player.visualizerAvailable;
} }
@Override @Override
@ -693,7 +512,7 @@ public class DownloadServiceImpl implements DownloadService
{ {
MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
if (mediaPlayerService == null) return null; if (mediaPlayerService == null) return null;
return mediaPlayerService.getEqualizerController(); return player.getEqualizerController();
} }
@Override @Override
@ -701,7 +520,7 @@ public class DownloadServiceImpl implements DownloadService
{ {
MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
if (mediaPlayerService == null) return null; if (mediaPlayerService == null) return null;
return mediaPlayerService.getVisualizerController(); return player.getVisualizerController();
} }
@Override @Override
@ -757,9 +576,9 @@ public class DownloadServiceImpl implements DownloadService
reset(); reset();
// Cancel current download, if necessary. // Cancel current download, if necessary.
if (MediaPlayerService.currentDownloading != null) if (downloader.currentDownloading != null)
{ {
MediaPlayerService.currentDownloading.cancelDownload(); downloader.currentDownloading.cancelDownload();
} }
} }
else else
@ -778,13 +597,13 @@ public class DownloadServiceImpl implements DownloadService
public void setVolume(float volume) public void setVolume(float volume)
{ {
MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
if (mediaPlayerService != null) mediaPlayerService.setVolume(volume); if (mediaPlayerService != null) player.setVolume(volume);
} }
@Override @Override
public synchronized void swap(boolean mainList, int from, int to) public synchronized void swap(boolean mainList, int from, int to)
{ {
List<DownloadFile> list = mainList ? MediaPlayerService.downloadList : MediaPlayerService.backgroundDownloadList; List<DownloadFile> list = mainList ? downloader.downloadList : downloader.backgroundDownloadList;
int max = list.size(); int max = list.size();
if (to >= max) if (to >= max)
@ -796,7 +615,7 @@ public class DownloadServiceImpl implements DownloadService
to = 0; to = 0;
} }
int currentPlayingIndex = getCurrentPlayingIndex(); int currentPlayingIndex = downloader.getCurrentPlayingIndex();
DownloadFile movedSong = list.remove(from); DownloadFile movedSong = list.remove(from);
list.add(to, movedSong); list.add(to, movedSong);
@ -804,7 +623,7 @@ public class DownloadServiceImpl implements DownloadService
{ {
jukeboxService.getValue().updatePlaylist(); jukeboxService.getValue().updatePlaylist();
} }
else if (mainList && (movedSong == MediaPlayerService.nextPlaying || (currentPlayingIndex + 1) == to)) else if (mainList && (movedSong == player.nextPlaying || (currentPlayingIndex + 1) == to))
{ {
// Moving next playing or moving a song to be next playing // Moving next playing or moving a song to be next playing
MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
@ -812,17 +631,11 @@ public class DownloadServiceImpl implements DownloadService
} }
} }
@Override
public long getDownloadListUpdateRevision()
{
return MediaPlayerService.revision;
}
@Override @Override
public void updateNotification() public void updateNotification()
{ {
MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance(); MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
if (mediaPlayerService != null) mediaPlayerService.updateNotification(); if (mediaPlayerService != null) mediaPlayerService.updateNotification(player.playerState, player.currentPlaying);
} }
public void setSongRating(final int rating) public void setSongRating(final int rating)
@ -830,10 +643,10 @@ public class DownloadServiceImpl implements DownloadService
if (!KoinJavaComponent.get(FeatureStorage.class).isFeatureEnabled(Feature.FIVE_STAR_RATING)) if (!KoinJavaComponent.get(FeatureStorage.class).isFeatureEnabled(Feature.FIVE_STAR_RATING))
return; return;
if (MediaPlayerService.currentPlaying == null) if (player.currentPlaying == null)
return; return;
final Entry song = MediaPlayerService.currentPlaying.getSong(); final Entry song = player.currentPlaying.getSong();
song.setUserRating(rating); song.setUserRating(rating);
new Thread(new Runnable() new Thread(new Runnable()

View File

@ -49,14 +49,16 @@ public class DownloadServiceLifecycleSupport
private Lazy<DownloadQueueSerializer> downloadQueueSerializer = inject(DownloadQueueSerializer.class); private Lazy<DownloadQueueSerializer> downloadQueueSerializer = inject(DownloadQueueSerializer.class);
private final DownloadServiceImpl downloadService; // From DI private final DownloadServiceImpl downloadService; // From DI
private final Downloader downloader; // From DI
private BroadcastReceiver headsetEventReceiver; private BroadcastReceiver headsetEventReceiver;
private Context context; private Context context;
public DownloadServiceLifecycleSupport(Context context, final DownloadServiceImpl downloadService) public DownloadServiceLifecycleSupport(Context context, final DownloadServiceImpl downloadService, final Downloader downloader)
{ {
this.downloadService = downloadService; this.downloadService = downloadService;
this.context = context; this.context = context;
this.downloader = downloader;
registerHeadsetReceiver(); registerHeadsetReceiver();
@ -80,8 +82,8 @@ public class DownloadServiceLifecycleSupport
downloadService.restore(state.songs, state.currentPlayingIndex, state.currentPlayingPosition, false, false); downloadService.restore(state.songs, state.currentPlayingIndex, state.currentPlayingPosition, false, false);
// Work-around: Serialize again, as the restore() method creates a serialization without current playing info. // Work-around: Serialize again, as the restore() method creates a serialization without current playing info.
downloadQueueSerializer.getValue().serializeDownloadQueue(downloadService.getSongs(), downloadQueueSerializer.getValue().serializeDownloadQueue(downloader.downloadList,
downloadService.getCurrentPlayingIndex(), downloadService.getPlayerPosition()); downloader.getCurrentPlayingIndex(), downloadService.getPlayerPosition());
} }
}); });
@ -165,7 +167,7 @@ public class DownloadServiceLifecycleSupport
downloadService.previous(); downloadService.previous();
break; break;
case KeyEvent.KEYCODE_MEDIA_NEXT: case KeyEvent.KEYCODE_MEDIA_NEXT:
if (downloadService.getCurrentPlayingIndex() < downloadService.size() - 1) if (downloader.getCurrentPlayingIndex() < downloader.downloadList.size() - 1)
{ {
downloadService.next(); downloadService.next();
} }

View File

@ -0,0 +1,454 @@
package org.moire.ultrasonic.service;
import android.content.Context;
import android.util.Log;
import org.moire.ultrasonic.domain.MusicDirectory;
import org.moire.ultrasonic.util.LRUCache;
import org.moire.ultrasonic.util.ShufflePlayBuffer;
import org.moire.ultrasonic.util.Util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import kotlin.Lazy;
import static org.koin.java.standalone.KoinJavaComponent.inject;
import static org.moire.ultrasonic.domain.PlayerState.DOWNLOADING;
import static org.moire.ultrasonic.domain.PlayerState.STARTED;
public class Downloader
{
private static final String TAG = Downloader.class.getSimpleName();
private final ShufflePlayBuffer shufflePlayBuffer;
private final ExternalStorageMonitor externalStorageMonitor;
private final Player player;
public Lazy<JukeboxService> jukeboxService = inject(JukeboxService.class);
public final List<DownloadFile> downloadList = new ArrayList<>();
public final List<DownloadFile> backgroundDownloadList = new ArrayList<>();
private final List<DownloadFile> cleanupCandidates = new ArrayList<>();
private final LRUCache<MusicDirectory.Entry, DownloadFile> downloadFileCache = new LRUCache<>(100);
public DownloadFile currentDownloading;
public static long revision;
private ScheduledExecutorService executorService;
private Context context;
public Downloader(Context context, ShufflePlayBuffer shufflePlayBuffer, ExternalStorageMonitor externalStorageMonitor,
Player player)
{
this.context = context;
this.shufflePlayBuffer = shufflePlayBuffer;
this.externalStorageMonitor = externalStorageMonitor;
this.player = player;
}
public void onCreate()
{
Runnable downloadChecker = new Runnable()
{
@Override
public void run()
{
try
{
checkDownloads();
}
catch (Throwable x)
{
Log.e(TAG, "checkDownloads() failed.", x);
}
}
};
executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleWithFixedDelay(downloadChecker, 5, 5, TimeUnit.SECONDS);
Log.i(TAG, "Downloader created");
}
public void onDestroy()
{
executorService.shutdown();
Log.i(TAG, "Downloader destroyed");
}
protected synchronized void checkDownloads()
{
if (!Util.isExternalStoragePresent() || !externalStorageMonitor.isExternalStorageAvailable())
{
return;
}
if (shufflePlayBuffer.isEnabled)
{
checkShufflePlay(context);
}
if (jukeboxService.getValue().isEnabled() || !Util.isNetworkConnected(context))
{
return;
}
if (downloadList.isEmpty() && backgroundDownloadList.isEmpty())
{
return;
}
// Need to download current playing?
if (player.currentPlaying != null && player.currentPlaying != currentDownloading && !player.currentPlaying.isWorkDone())
{
// Cancel current download, if necessary.
if (currentDownloading != null)
{
currentDownloading.cancelDownload();
}
currentDownloading = player.currentPlaying;
currentDownloading.download();
cleanupCandidates.add(currentDownloading);
// Delete obsolete .partial and .complete files.
cleanup();
return;
}
// Find a suitable target for download.
if (currentDownloading != null &&
!currentDownloading.isWorkDone() &&
(!currentDownloading.isFailed() || (downloadList.isEmpty() && backgroundDownloadList.isEmpty())))
{
cleanup();
return;
}
// There is a target to download
currentDownloading = null;
int n = downloadList.size();
int preloaded = 0;
if (n != 0)
{
int start = player.currentPlaying == null ? 0 : getCurrentPlayingIndex();
if (start == -1) start = 0;
int i = start;
do
{
DownloadFile downloadFile = downloadList.get(i);
if (!downloadFile.isWorkDone())
{
if (downloadFile.shouldSave() || preloaded < Util.getPreloadCount(context))
{
currentDownloading = downloadFile;
currentDownloading.download();
cleanupCandidates.add(currentDownloading);
if (i == (start + 1))
{
player.setNextPlayerState(DOWNLOADING);
}
break;
}
}
else if (player.currentPlaying != downloadFile)
{
preloaded++;
}
i = (i + 1) % n;
} while (i != start);
}
if ((preloaded + 1 == n || preloaded >= Util.getPreloadCount(context) || downloadList.isEmpty()) && !backgroundDownloadList.isEmpty())
{
for (int i = 0; i < backgroundDownloadList.size(); i++)
{
DownloadFile downloadFile = backgroundDownloadList.get(i);
if (downloadFile.isWorkDone() && (!downloadFile.shouldSave() || downloadFile.isSaved()))
{
if (Util.getShouldScanMedia(context))
{
Util.scanMedia(context, downloadFile.getCompleteFile());
}
// Don't need to keep list like active song list
backgroundDownloadList.remove(i);
revision++;
i--;
}
else
{
currentDownloading = downloadFile;
currentDownloading.download();
cleanupCandidates.add(currentDownloading);
break;
}
}
}
// Delete obsolete .partial and .complete files.
cleanup();
}
public synchronized int getCurrentPlayingIndex()
{
return downloadList.indexOf(player.currentPlaying);
}
public long getDownloadListDuration()
{
long totalDuration = 0;
for (DownloadFile downloadFile : downloadList)
{
MusicDirectory.Entry entry = downloadFile.getSong();
if (!entry.isDirectory())
{
if (entry.getArtist() != null)
{
Integer duration = entry.getDuration();
if (duration != null)
{
totalDuration += duration;
}
}
}
}
return totalDuration;
}
public synchronized List<DownloadFile> getDownloads()
{
List<DownloadFile> temp = new ArrayList<>();
temp.addAll(downloadList);
temp.addAll(backgroundDownloadList);
return temp;
}
public List<DownloadFile> getBackgroundDownloads()
{
return backgroundDownloadList;
}
public long getDownloadListUpdateRevision()
{
return revision;
}
public synchronized void clear()
{
downloadList.clear();
revision++;
if (currentDownloading != null)
{
currentDownloading.cancelDownload();
currentDownloading = null;
}
}
public synchronized void clearBackground()
{
if (currentDownloading != null && backgroundDownloadList.contains(currentDownloading))
{
currentDownloading.cancelDownload();
currentDownloading = null;
}
backgroundDownloadList.clear();
}
public synchronized void removeDownloadFile(DownloadFile downloadFile)
{
if (downloadFile == currentDownloading)
{
currentDownloading.cancelDownload();
currentDownloading = null;
}
downloadList.remove(downloadFile);
backgroundDownloadList.remove(downloadFile);
revision++;
}
public synchronized void download(List<MusicDirectory.Entry> songs, boolean save, boolean autoPlay, boolean playNext, boolean newPlaylist)
{
shufflePlayBuffer.isEnabled = false;
int offset = 1;
if (songs.isEmpty())
{
return;
}
if (newPlaylist)
{
downloadList.clear();
}
if (playNext)
{
if (autoPlay && getCurrentPlayingIndex() >= 0)
{
offset = 0;
}
for (MusicDirectory.Entry song : songs)
{
DownloadFile downloadFile = new DownloadFile(context, song, save);
downloadList.add(getCurrentPlayingIndex() + offset, downloadFile);
offset++;
}
}
else
{
for (MusicDirectory.Entry song : songs)
{
DownloadFile downloadFile = new DownloadFile(context, song, save);
downloadList.add(downloadFile);
}
}
revision++;
}
public synchronized void downloadBackground(List<MusicDirectory.Entry> songs, boolean save)
{
for (MusicDirectory.Entry song : songs)
{
DownloadFile downloadFile = new DownloadFile(context, song, save);
backgroundDownloadList.add(downloadFile);
}
revision++;
checkDownloads();
}
public synchronized void shuffle()
{
Collections.shuffle(downloadList);
if (player.currentPlaying != null)
{
downloadList.remove(getCurrentPlayingIndex());
downloadList.add(0, player.currentPlaying);
}
revision++;
}
public synchronized void setFirstPlaying()
{
if (player.currentPlaying == null)
{
player.currentPlaying = downloadList.get(0);
player.currentPlaying.setPlaying(true);
}
checkDownloads();
}
public synchronized DownloadFile getDownloadFileForSong(MusicDirectory.Entry song)
{
for (DownloadFile downloadFile : downloadList)
{
if (downloadFile.getSong().equals(song) && ((downloadFile.isDownloading() && !downloadFile.isDownloadCancelled() && downloadFile.getPartialFile().exists()) || downloadFile.isWorkDone()))
{
return downloadFile;
}
}
for (DownloadFile downloadFile : backgroundDownloadList)
{
if (downloadFile.getSong().equals(song))
{
return downloadFile;
}
}
DownloadFile downloadFile = downloadFileCache.get(song);
if (downloadFile == null)
{
downloadFile = new DownloadFile(context, song, false);
downloadFileCache.put(song, downloadFile);
}
return downloadFile;
}
private synchronized void cleanup()
{
Iterator<DownloadFile> iterator = cleanupCandidates.iterator();
while (iterator.hasNext())
{
DownloadFile downloadFile = iterator.next();
if (downloadFile != player.currentPlaying && downloadFile != currentDownloading)
{
if (downloadFile.cleanup())
{
iterator.remove();
}
}
}
}
private synchronized void checkShufflePlay(Context context)
{
// Get users desired random playlist size
int listSize = Util.getMaxSongs(context);
boolean wasEmpty = downloadList.isEmpty();
long revisionBefore = revision;
// First, ensure that list is at least 20 songs long.
int size = downloadList.size();
if (size < listSize)
{
for (MusicDirectory.Entry song : shufflePlayBuffer.get(listSize - size))
{
DownloadFile downloadFile = new DownloadFile(context, song, false);
downloadList.add(downloadFile);
revision++;
}
}
int currIndex = player.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(context, song, false));
downloadList.get(0).cancelDownload();
downloadList.remove(0);
revision++;
}
}
if (revisionBefore != revision)
{
jukeboxService.getValue().updatePlaylist();
}
if (wasEmpty && !downloadList.isEmpty())
{
if (jukeboxService.getValue().isEnabled())
{
jukeboxService.getValue().skip(0, 0);
player.setPlayerState(STARTED);
}
else
{
player.play(downloadList.get(0));
}
}
}
}

View File

@ -71,7 +71,9 @@ public class JukeboxService
private boolean enabled = false; private boolean enabled = false;
private Context context; private Context context;
// TODO: These create circular references, try to refactor
private Lazy<DownloadServiceImpl> downloadServiceImpl = inject(DownloadServiceImpl.class); private Lazy<DownloadServiceImpl> downloadServiceImpl = inject(DownloadServiceImpl.class);
private final Downloader downloader;
// TODO: Report warning if queue fills up. // TODO: Report warning if queue fills up.
// TODO: Create shutdown method? // TODO: Create shutdown method?
@ -79,9 +81,10 @@ public class JukeboxService
// TODO: Persist RC state? // TODO: Persist RC state?
// TODO: Minimize status updates. // TODO: Minimize status updates.
public JukeboxService(Context context) public JukeboxService(Context context, Downloader downloader)
{ {
this.context = context; this.context = context;
this.downloader = downloader;
} }
public void startJukeboxService() public void startJukeboxService()
@ -182,7 +185,7 @@ public class JukeboxService
// Track change? // Track change?
Integer index = jukeboxStatus.getCurrentPlayingIndex(); Integer index = jukeboxStatus.getCurrentPlayingIndex();
if (index != null && index != -1 && index != downloadServiceImpl.getValue().getCurrentPlayingIndex()) if (index != null && index != -1 && index != downloader.getCurrentPlayingIndex())
{ {
downloadServiceImpl.getValue().setCurrentPlaying(index); downloadServiceImpl.getValue().setCurrentPlaying(index);
} }
@ -232,8 +235,8 @@ public class JukeboxService
tasks.remove(Stop.class); tasks.remove(Stop.class);
tasks.remove(Start.class); tasks.remove(Start.class);
List<String> ids = new ArrayList<String>(); List<String> ids = new ArrayList<>();
for (DownloadFile file : downloadServiceImpl.getValue().getDownloads()) for (DownloadFile file : downloader.getDownloads())
{ {
ids.add(file.getSong().getId()); ids.add(file.getSong().getId());
} }
@ -334,7 +337,7 @@ public class JukeboxService
private static class TaskQueue private static class TaskQueue
{ {
private final LinkedBlockingQueue<JukeboxTask> queue = new LinkedBlockingQueue<JukeboxTask>(); private final LinkedBlockingQueue<JukeboxTask> queue = new LinkedBlockingQueue<>();
void add(JukeboxTask jukeboxTask) void add(JukeboxTask jukeboxTask)
{ {

File diff suppressed because it is too large Load Diff

View File

@ -7,8 +7,7 @@ import android.util.Log;
import org.moire.ultrasonic.domain.Playlist; import org.moire.ultrasonic.domain.Playlist;
import org.moire.ultrasonic.service.DownloadFile; import org.moire.ultrasonic.service.DownloadFile;
import org.moire.ultrasonic.service.DownloadService; import org.moire.ultrasonic.service.Downloader;
import org.moire.ultrasonic.service.DownloadServiceImpl;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
@ -35,7 +34,7 @@ public class CacheCleaner
private static final long MIN_FREE_SPACE = 500 * 1024L * 1024L; private static final long MIN_FREE_SPACE = 500 * 1024L * 1024L;
private final Context context; private final Context context;
private Lazy<DownloadServiceImpl> downloadServiceImpl = inject(DownloadServiceImpl.class); private Lazy<Downloader> downloader = inject(Downloader.class);
public CacheCleaner(Context context) public CacheCleaner(Context context)
{ {
@ -223,7 +222,7 @@ public class CacheCleaner
{ {
Set<File> filesToNotDelete = new HashSet<File>(5); Set<File> filesToNotDelete = new HashSet<File>(5);
for (DownloadFile downloadFile : downloadServiceImpl.getValue().getDownloads()) for (DownloadFile downloadFile : downloader.getValue().getDownloads())
{ {
filesToNotDelete.add(downloadFile.getPartialFile()); filesToNotDelete.add(downloadFile.getPartialFile());
filesToNotDelete.add(downloadFile.getCompleteFile()); filesToNotDelete.add(downloadFile.getCompleteFile());

View File

@ -37,19 +37,24 @@ import java.util.concurrent.TimeUnit;
*/ */
public class ShufflePlayBuffer public class ShufflePlayBuffer
{ {
private static final String TAG = ShufflePlayBuffer.class.getSimpleName(); private static final String TAG = ShufflePlayBuffer.class.getSimpleName();
private static final int CAPACITY = 50; private static final int CAPACITY = 50;
private static final int REFILL_THRESHOLD = 40; private static final int REFILL_THRESHOLD = 40;
private final ScheduledExecutorService executorService;
private final List<MusicDirectory.Entry> buffer = new ArrayList<MusicDirectory.Entry>(); private final List<MusicDirectory.Entry> buffer = new ArrayList<MusicDirectory.Entry>();
private final Context context; private final Context context;
private ScheduledExecutorService executorService;
private int currentServer; private int currentServer;
public boolean isEnabled = false;
public ShufflePlayBuffer(Context context) public ShufflePlayBuffer(Context context)
{ {
this.context = context; this.context = context;
}
public void onCreate()
{
executorService = Executors.newSingleThreadScheduledExecutor(); executorService = Executors.newSingleThreadScheduledExecutor();
Runnable runnable = new Runnable() Runnable runnable = new Runnable()
{ {
@ -62,6 +67,11 @@ public class ShufflePlayBuffer
executorService.scheduleWithFixedDelay(runnable, 1, 10, TimeUnit.SECONDS); executorService.scheduleWithFixedDelay(runnable, 1, 10, TimeUnit.SECONDS);
} }
public void onDestroy()
{
executorService.shutdown();
}
public List<MusicDirectory.Entry> get(int size) public List<MusicDirectory.Entry> get(int size)
{ {
clearBufferIfNecessary(); clearBufferIfNecessary();
@ -78,13 +88,9 @@ public class ShufflePlayBuffer
return result; return result;
} }
public void shutdown()
{
executorService.shutdown();
}
private void refill() private void refill()
{ {
if (!isEnabled) return;
// Check if active server has changed. // Check if active server has changed.
clearBufferIfNecessary(); clearBufferIfNecessary();

View File

@ -57,6 +57,7 @@ import org.moire.ultrasonic.service.DownloadFile;
import org.moire.ultrasonic.service.DownloadService; import org.moire.ultrasonic.service.DownloadService;
import org.moire.ultrasonic.service.DownloadServiceImpl; import org.moire.ultrasonic.service.DownloadServiceImpl;
import org.moire.ultrasonic.service.DownloadServiceLifecycleSupport; import org.moire.ultrasonic.service.DownloadServiceLifecycleSupport;
import org.moire.ultrasonic.service.Downloader;
import org.moire.ultrasonic.service.MediaPlayerService; import org.moire.ultrasonic.service.MediaPlayerService;
import org.moire.ultrasonic.service.MusicServiceFactory; import org.moire.ultrasonic.service.MusicServiceFactory;
@ -960,7 +961,7 @@ public class Util extends DownloadActivity
context.sendBroadcast(intent); context.sendBroadcast(intent);
} }
public static void broadcastA2dpMetaDataChange(Context context, DownloadService downloadService) public static void broadcastA2dpMetaDataChange(Context context, int playerPosition, DownloadFile currentPlaying, int listSize, int id)
{ {
if (!Util.getShouldSendBluetoothNotifications(context)) if (!Util.getShouldSendBluetoothNotifications(context))
{ {
@ -970,17 +971,9 @@ public class Util extends DownloadActivity
Entry song = null; Entry song = null;
Intent avrcpIntent = new Intent(CM_AVRCP_METADATA_CHANGED); Intent avrcpIntent = new Intent(CM_AVRCP_METADATA_CHANGED);
if (downloadService != null) if (currentPlaying != null) song = currentPlaying.getSong();
{
DownloadFile entry = downloadService.getCurrentPlaying();
if (entry != null) if (song == null)
{
song = entry.getSong();
}
}
if (downloadService == null || song == null)
{ {
avrcpIntent.putExtra("track", ""); avrcpIntent.putExtra("track", "");
avrcpIntent.putExtra("track_name", ""); avrcpIntent.putExtra("track_name", "");
@ -1013,9 +1006,6 @@ public class Util extends DownloadActivity
String artist = song.getArtist(); String artist = song.getArtist();
String album = song.getAlbum(); String album = song.getAlbum();
Integer duration = song.getDuration(); Integer duration = song.getDuration();
Integer listSize = downloadService.getDownloads().size();
Integer id = downloadService.getCurrentPlayingIndex() + 1;
Integer playerPosition = downloadService.getPlayerPosition();
avrcpIntent.putExtra("track", title); avrcpIntent.putExtra("track", title);
avrcpIntent.putExtra("track_name", title); avrcpIntent.putExtra("track_name", title);

View File

@ -39,8 +39,10 @@ import org.moire.ultrasonic.featureflags.FeatureStorage;
import org.moire.ultrasonic.service.DownloadFile; import org.moire.ultrasonic.service.DownloadFile;
import org.moire.ultrasonic.service.DownloadService; import org.moire.ultrasonic.service.DownloadService;
import org.moire.ultrasonic.service.DownloadServiceImpl; import org.moire.ultrasonic.service.DownloadServiceImpl;
import org.moire.ultrasonic.service.Downloader;
import org.moire.ultrasonic.service.MusicService; import org.moire.ultrasonic.service.MusicService;
import org.moire.ultrasonic.service.MusicServiceFactory; import org.moire.ultrasonic.service.MusicServiceFactory;
import org.moire.ultrasonic.service.Player;
import org.moire.ultrasonic.util.Util; import org.moire.ultrasonic.util.Util;
import org.moire.ultrasonic.util.VideoPlayerType; import org.moire.ultrasonic.util.VideoPlayerType;
@ -82,7 +84,8 @@ public class SongView extends UpdateView implements Checkable
private boolean maximized = false; private boolean maximized = false;
private boolean useFiveStarRating; private boolean useFiveStarRating;
private Lazy<DownloadServiceImpl> downloadServiceImpl = inject(DownloadServiceImpl.class); private Lazy<Downloader> downloader = inject(Downloader.class);
protected Lazy<Player> player = inject(Player.class);
public SongView(Context context) public SongView(Context context)
{ {
@ -169,7 +172,7 @@ public class SongView extends UpdateView implements Checkable
this.song = song; this.song = song;
this.downloadFile = downloadServiceImpl.getValue().forSong(song); this.downloadFile = downloader.getValue().getDownloadFileForSong(song);
StringBuilder artist = new StringBuilder(60); StringBuilder artist = new StringBuilder(60);
@ -320,7 +323,7 @@ public class SongView extends UpdateView implements Checkable
{ {
updateBackground(); updateBackground();
downloadFile = downloadServiceImpl.getValue().forSong(this.song); downloadFile = downloader.getValue().getDownloadFileForSong(this.song);
File partialFile = downloadFile.getPartialFile(); File partialFile = downloadFile.getPartialFile();
if (downloadFile.isWorkDone()) if (downloadFile.isWorkDone())
@ -410,7 +413,7 @@ public class SongView extends UpdateView implements Checkable
viewHolder.fiveStar4.setImageDrawable(rating > 3 ? starDrawable : starHollowDrawable); viewHolder.fiveStar4.setImageDrawable(rating > 3 ? starDrawable : starHollowDrawable);
viewHolder.fiveStar5.setImageDrawable(rating > 4 ? starDrawable : starHollowDrawable); viewHolder.fiveStar5.setImageDrawable(rating > 4 ? starDrawable : starHollowDrawable);
boolean playing = downloadServiceImpl.getValue().getCurrentPlaying() == downloadFile; boolean playing = player.getValue().currentPlaying == downloadFile;
if (playing) if (playing)
{ {

View File

@ -15,6 +15,7 @@ import org.moire.ultrasonic.cache.PermanentFileStorage
import org.moire.ultrasonic.service.* import org.moire.ultrasonic.service.*
import org.moire.ultrasonic.subsonic.loader.image.SubsonicImageLoader import org.moire.ultrasonic.subsonic.loader.image.SubsonicImageLoader
import org.moire.ultrasonic.util.Constants import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.ShufflePlayBuffer
internal const val MUSIC_SERVICE_CONTEXT = "CurrentMusicService" internal const val MUSIC_SERVICE_CONTEXT = "CurrentMusicService"
internal const val ONLINE_MUSIC_SERVICE = "OnlineMusicService" internal const val ONLINE_MUSIC_SERVICE = "OnlineMusicService"
@ -112,9 +113,12 @@ val musicServiceModule = module(MUSIC_SERVICE_CONTEXT) {
single { SubsonicImageLoader(getProperty(DiProperties.APP_CONTEXT), get()) } single { SubsonicImageLoader(getProperty(DiProperties.APP_CONTEXT), get()) }
single { DownloadServiceImpl(androidContext()) } single { DownloadServiceImpl(androidContext(), get(), get(), get()) }
single { JukeboxService(androidContext()) } single { JukeboxService(androidContext(), get()) }
single { DownloadServiceLifecycleSupport(androidContext(), get())} single { DownloadServiceLifecycleSupport(androidContext(), get(), get()) }
single { DownloadQueueSerializer(androidContext())} single { DownloadQueueSerializer(androidContext()) }
single { ExternalStorageMonitor(androidContext())} single { ExternalStorageMonitor(androidContext()) }
single { ShufflePlayBuffer(androidContext()) }
single { Downloader(androidContext(), get(), get(), get()) }
single { Player(androidContext()) }
} }