From 3cc5dfa96f67899ada68a69b3e21816c3431b438 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Sun, 11 Aug 2013 08:58:30 -0700 Subject: Use JukeboxController instead of JukeboxService --- .../daneren2005/dsub/domain/JukeboxStatus.java | 63 ---- .../daneren2005/dsub/domain/RemoteStatus.java | 63 ++++ .../dsub/service/CachedMusicService.java | 14 +- .../dsub/service/DownloadServiceImpl.java | 59 ++-- .../dsub/service/JukeboxController.java | 111 +++---- .../daneren2005/dsub/service/JukeboxService.java | 359 --------------------- .../daneren2005/dsub/service/MusicService.java | 15 +- .../dsub/service/OfflineMusicService.java | 15 +- .../daneren2005/dsub/service/RESTMusicService.java | 21 +- .../daneren2005/dsub/service/RemoteController.java | 51 ++- .../dsub/service/parser/JukeboxStatusParser.java | 6 +- 11 files changed, 225 insertions(+), 552 deletions(-) delete mode 100644 src/github/daneren2005/dsub/domain/JukeboxStatus.java create mode 100644 src/github/daneren2005/dsub/domain/RemoteStatus.java delete mode 100644 src/github/daneren2005/dsub/service/JukeboxService.java (limited to 'src') diff --git a/src/github/daneren2005/dsub/domain/JukeboxStatus.java b/src/github/daneren2005/dsub/domain/JukeboxStatus.java deleted file mode 100644 index 7b229f49..00000000 --- a/src/github/daneren2005/dsub/domain/JukeboxStatus.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public class JukeboxStatus { - - private Integer positionSeconds; - private Integer currentPlayingIndex; - private Float gain; - private boolean playing; - - public Integer getPositionSeconds() { - return positionSeconds; - } - - public void setPositionSeconds(Integer positionSeconds) { - this.positionSeconds = positionSeconds; - } - - public Integer getCurrentPlayingIndex() { - return currentPlayingIndex; - } - - public void setCurrentIndex(Integer currentPlayingIndex) { - this.currentPlayingIndex = currentPlayingIndex; - } - - public boolean isPlaying() { - return playing; - } - - public void setPlaying(boolean playing) { - this.playing = playing; - } - - public Float getGain() { - return gain; - } - - public void setGain(float gain) { - this.gain = gain; - } -} diff --git a/src/github/daneren2005/dsub/domain/RemoteStatus.java b/src/github/daneren2005/dsub/domain/RemoteStatus.java new file mode 100644 index 00000000..e9749120 --- /dev/null +++ b/src/github/daneren2005/dsub/domain/RemoteStatus.java @@ -0,0 +1,63 @@ +/* + This file is part of Subsonic. + + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see . + + Copyright 2009 (C) Sindre Mehus + */ +package github.daneren2005.dsub.domain; + +/** + * @author Sindre Mehus + * @version $Id$ + */ +public class RemoteStatus { + + private Integer positionSeconds; + private Integer currentPlayingIndex; + private Float gain; + private boolean playing; + + public Integer getPositionSeconds() { + return positionSeconds; + } + + public void setPositionSeconds(Integer positionSeconds) { + this.positionSeconds = positionSeconds; + } + + public Integer getCurrentPlayingIndex() { + return currentPlayingIndex; + } + + public void setCurrentIndex(Integer currentPlayingIndex) { + this.currentPlayingIndex = currentPlayingIndex; + } + + public boolean isPlaying() { + return playing; + } + + public void setPlaying(boolean playing) { + this.playing = playing; + } + + public Float getGain() { + return gain; + } + + public void setGain(float gain) { + this.gain = gain; + } +} diff --git a/src/github/daneren2005/dsub/service/CachedMusicService.java b/src/github/daneren2005/dsub/service/CachedMusicService.java index 943b5eb2..cc8d2dbd 100644 --- a/src/github/daneren2005/dsub/service/CachedMusicService.java +++ b/src/github/daneren2005/dsub/service/CachedMusicService.java @@ -29,7 +29,7 @@ import android.support.v4.util.LruCache; import github.daneren2005.dsub.domain.ChatMessage; import github.daneren2005.dsub.domain.Genre; import github.daneren2005.dsub.domain.Indexes; -import github.daneren2005.dsub.domain.JukeboxStatus; +import github.daneren2005.dsub.domain.RemoteStatus; import github.daneren2005.dsub.domain.Lyrics; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.MusicFolder; @@ -241,32 +241,32 @@ public class CachedMusicService implements MusicService { } @Override - public JukeboxStatus updateJukeboxPlaylist(List ids, Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus updateJukeboxPlaylist(List ids, Context context, ProgressListener progressListener) throws Exception { return musicService.updateJukeboxPlaylist(ids, context, progressListener); } @Override - public JukeboxStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception { return musicService.skipJukebox(index, offsetSeconds, context, progressListener); } @Override - public JukeboxStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception { return musicService.stopJukebox(context, progressListener); } @Override - public JukeboxStatus startJukebox(Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus startJukebox(Context context, ProgressListener progressListener) throws Exception { return musicService.startJukebox(context, progressListener); } @Override - public JukeboxStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception { return musicService.getJukeboxStatus(context, progressListener); } @Override - public JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception { return musicService.setJukeboxGain(gain, context, progressListener); } diff --git a/src/github/daneren2005/dsub/service/DownloadServiceImpl.java b/src/github/daneren2005/dsub/service/DownloadServiceImpl.java index 85991abb..9568c0af 100644 --- a/src/github/daneren2005/dsub/service/DownloadServiceImpl.java +++ b/src/github/daneren2005/dsub/service/DownloadServiceImpl.java @@ -99,7 +99,7 @@ public class DownloadServiceImpl extends Service implements DownloadService { private final LruCache downloadFileCache = new LruCache(100); private final List cleanupCandidates = new ArrayList(); private final Scrobbler scrobbler = new Scrobbler(); - private final JukeboxService jukeboxService = new JukeboxService(this); + private RemoteController remoteController; private DownloadFile currentPlaying; private DownloadFile nextPlaying; private DownloadFile currentDownloading; @@ -324,15 +324,15 @@ public class DownloadServiceImpl extends Service implements DownloadService { private void updateJukeboxPlaylist() { if (remoteState != RemoteControlState.LOCAL) { - jukeboxService.updatePlaylist(); + remoteController.updatePlaylist(); } } public void restore(List songs, int currentPlayingIndex, int currentPlayingPosition) { SharedPreferences prefs = Util.getPreferences(this); remoteState = RemoteControlState.values()[prefs.getInt(Constants.PREFERENCES_KEY_CONTROL_MODE, 0)]; - if(remoteState == RemoteControlState.JUKEBOX_SERVER) { - jukeboxService.setEnabled(true); + if(remoteState != RemoteControlState.LOCAL) { + setRemoteState(remoteState); } boolean startShufflePlay = prefs.getBoolean(Constants.PREFERENCES_KEY_SHUFFLE_MODE, false); download(songs, false, false, false, false); @@ -667,7 +667,7 @@ public class DownloadServiceImpl extends Service implements DownloadService { setCurrentPlaying(index, start); if (start) { if (remoteState != RemoteControlState.LOCAL) { - jukeboxService.skip(getCurrentPlayingIndex(), 0); + remoteController.changeTrack(getCurrentPlayingIndex(), currentPlaying); setPlayerState(STARTED); } else { bufferAndPlay(); @@ -727,7 +727,7 @@ public class DownloadServiceImpl extends Service implements DownloadService { public synchronized void seekTo(int position) { try { if (remoteState != RemoteControlState.LOCAL) { - jukeboxService.skip(getCurrentPlayingIndex(), position / 1000); + remoteController.changePosition(position / 1000); } else { mediaPlayer.seekTo(position); cachedPosition = position; @@ -784,7 +784,7 @@ public class DownloadServiceImpl extends Service implements DownloadService { try { if (playerState == STARTED) { if (remoteState != RemoteControlState.LOCAL) { - jukeboxService.stop(); + remoteController.stop(); } else { mediaPlayer.pause(); } @@ -800,7 +800,7 @@ public class DownloadServiceImpl extends Service implements DownloadService { try { if (playerState == STARTED) { if (remoteState != RemoteControlState.LOCAL) { - jukeboxService.stop(); + remoteController.stop(); } else { mediaPlayer.pause(); } @@ -817,7 +817,7 @@ public class DownloadServiceImpl extends Service implements DownloadService { public synchronized void start() { try { if (remoteState != RemoteControlState.LOCAL) { - jukeboxService.start(); + remoteController.start(); } else { mediaPlayer.start(); } @@ -849,7 +849,7 @@ public class DownloadServiceImpl extends Service implements DownloadService { return 0; } if (remoteState != RemoteControlState.LOCAL) { - return jukeboxService.getPositionSeconds() * 1000; + return remoteController.getRemotePosition() * 1000; } else { return cachedPosition; } @@ -1028,25 +1028,42 @@ public class DownloadServiceImpl extends Service implements DownloadService { @Override public void setRemoteEnabled(RemoteControlState newState) { - remoteState = newState; - jukeboxService.setEnabled(remoteState == RemoteControlState.JUKEBOX_SERVER); - if (remoteState != RemoteControlState.LOCAL) { - reset(); - - // Cancel current download, if necessary. - if (currentDownloading != null) { - currentDownloading.cancelDownload(); - } - } + setRemoteState(newState); SharedPreferences.Editor editor = Util.getPreferences(this).edit(); editor.putInt(Constants.PREFERENCES_KEY_CONTROL_MODE, newState.getValue()); editor.commit(); } + private void setRemoteState(RemoteControlState newState) { + if(remoteController != null) { + remoteController.stop(); + setPlayerState(PlayerState.IDLE); + remoteController.shutdown(); + remoteController = null; + } + + remoteState = newState; + switch(newState) { + case JUKEBOX_SERVER: + remoteController = new JukeboxController(this); + break; + case LOCAL: default: + break; + } + + if (remoteState != RemoteControlState.LOCAL) { + reset(); + + // Cancel current download, if necessary. + if (currentDownloading != null) { + currentDownloading.cancelDownload(); + } + } + } @Override public void setRemoteVolume(boolean up) { - jukeboxService.adjustVolume(up); + remoteController.setVolume(up); } private synchronized void bufferAndPlay() { diff --git a/src/github/daneren2005/dsub/service/JukeboxController.java b/src/github/daneren2005/dsub/service/JukeboxController.java index 4a3d4d40..f27a147f 100644 --- a/src/github/daneren2005/dsub/service/JukeboxController.java +++ b/src/github/daneren2005/dsub/service/JukeboxController.java @@ -15,16 +15,11 @@ package github.daneren2005.dsub.service; -import android.content.Context; import android.os.Handler; import android.util.Log; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ProgressBar; -import android.widget.Toast; + import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.JukeboxStatus; +import github.daneren2005.dsub.domain.RemoteStatus; import github.daneren2005.dsub.domain.PlayerState; import github.daneren2005.dsub.domain.RemoteControlState; import github.daneren2005.dsub.service.parser.SubsonicRESTException; @@ -41,15 +36,16 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; public class JukeboxController extends RemoteController { - private static final String TAG = JukeboxService.class.getSimpleName(); + private static final String TAG = JukeboxController.class.getSimpleName(); private static final long STATUS_UPDATE_INTERVAL_SECONDS = 5L; private final Handler handler = new Handler(); + private boolean running = false; private final TaskQueue tasks = new TaskQueue(); private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); private ScheduledFuture statusUpdateFuture; private final AtomicLong timeOfLastUpdate = new AtomicLong(); - private JukeboxStatus jukeboxStatus; + private RemoteStatus jukeboxStatus; private float gain = 0.5f; public JukeboxController(DownloadServiceImpl downloadService) { @@ -57,10 +53,10 @@ public class JukeboxController extends RemoteController { new Thread() { @Override public void run() { + running = true; processTasks(); } }.start(); - downloadService.setPlayerState(PlayerState.IDLE); updatePlaylist(); } @@ -80,6 +76,10 @@ public class JukeboxController extends RemoteController { stopStatusUpdate(); tasks.add(new Stop()); } + @Override + public void shutdown() { + running = false; + } @Override public void updatePlaylist() { @@ -95,8 +95,7 @@ public class JukeboxController extends RemoteController { } @Override public void changePosition(int seconds) { - // TODO: Break down into changePosition/changeTrack - /*tasks.remove(Skip.class); + tasks.remove(Skip.class); tasks.remove(Stop.class); tasks.remove(Start.class); @@ -104,8 +103,8 @@ public class JukeboxController extends RemoteController { if (jukeboxStatus != null) { jukeboxStatus.setPositionSeconds(seconds); } - tasks.add(new Skip(index, seconds)); - downloadService.setPlayerState(PlayerState.STARTED);*/ + tasks.add(new Skip(-1, seconds)); + downloadService.setPlayerState(PlayerState.STARTED); } @Override public void changeTrack(int index, DownloadFile song) { @@ -144,12 +143,14 @@ public class JukeboxController extends RemoteController { } private void processTasks() { - while (true) { - JukeboxTask task = null; + while (running) { + RemoteTask task = null; try { task = tasks.take(); - JukeboxStatus status = task.execute(); - onStatusUpdate(status); + RemoteStatus status = task.execute(); + if(status != null) { + onStatusUpdate(status); + } } catch (Throwable x) { onError(task, x); } @@ -176,7 +177,7 @@ public class JukeboxController extends RemoteController { } } - private void onStatusUpdate(JukeboxStatus jukeboxStatus) { + private void onStatusUpdate(RemoteStatus jukeboxStatus) { timeOfLastUpdate.set(System.currentTimeMillis()); this.jukeboxStatus = jukeboxStatus; @@ -189,7 +190,7 @@ public class JukeboxController extends RemoteController { } } - private void onError(JukeboxTask task, Throwable x) { + private void onError(RemoteTask task, Throwable x) { if (x instanceof ServerTooOldException && !(task instanceof Stop)) { disableJukeboxOnError(x, R.string.download_jukebox_server_too_old); } else if (x instanceof OfflineException && !(task instanceof Stop)) { @@ -215,54 +216,15 @@ public class JukeboxController extends RemoteController { private MusicService getMusicService() { return MusicServiceFactory.getMusicService(downloadService); } - - private static class TaskQueue { - private final LinkedBlockingQueue queue = new LinkedBlockingQueue(); - - void add(JukeboxTask jukeboxTask) { - queue.add(jukeboxTask); - } - - JukeboxTask take() throws InterruptedException { - return queue.take(); - } - - void remove(Class clazz) { - try { - Iterator iterator = queue.iterator(); - while (iterator.hasNext()) { - JukeboxTask task = iterator.next(); - if (clazz.equals(task.getClass())) { - iterator.remove(); - } - } - } catch (Throwable x) { - Log.w(TAG, "Failed to clean-up task queue.", x); - } - } - - void clear() { - queue.clear(); - } - } - - private abstract class JukeboxTask { - abstract JukeboxStatus execute() throws Exception; - - @Override - public String toString() { - return getClass().getSimpleName(); - } - } - private class GetStatus extends JukeboxTask { + private class GetStatus extends RemoteTask { @Override - JukeboxStatus execute() throws Exception { + RemoteStatus execute() throws Exception { return getMusicService().getJukeboxStatus(downloadService, null); } } - private class SetPlaylist extends JukeboxTask { + private class SetPlaylist extends RemoteTask { private final List ids; SetPlaylist(List ids) { @@ -270,12 +232,12 @@ public class JukeboxController extends RemoteController { } @Override - JukeboxStatus execute() throws Exception { + RemoteStatus execute() throws Exception { return getMusicService().updateJukeboxPlaylist(ids, downloadService, null); } } - private class Skip extends JukeboxTask { + private class Skip extends RemoteTask { private final int index; private final int offsetSeconds; @@ -285,26 +247,26 @@ public class JukeboxController extends RemoteController { } @Override - JukeboxStatus execute() throws Exception { + RemoteStatus execute() throws Exception { return getMusicService().skipJukebox(index, offsetSeconds, downloadService, null); } } - private class Stop extends JukeboxTask { + private class Stop extends RemoteTask { @Override - JukeboxStatus execute() throws Exception { + RemoteStatus execute() throws Exception { return getMusicService().stopJukebox(downloadService, null); } } - private class Start extends JukeboxTask { + private class Start extends RemoteTask { @Override - JukeboxStatus execute() throws Exception { + RemoteStatus execute() throws Exception { return getMusicService().startJukebox(downloadService, null); } } - private class SetGain extends JukeboxTask { + private class SetGain extends RemoteTask { private final float gain; private SetGain(float gain) { @@ -312,8 +274,15 @@ public class JukeboxController extends RemoteController { } @Override - JukeboxStatus execute() throws Exception { + RemoteStatus execute() throws Exception { return getMusicService().setJukeboxGain(gain, downloadService, null); } } + + private class ShutdownTask extends RemoteTask { + @Override + RemoteStatus execute() throws Exception { + return null; + } + } } diff --git a/src/github/daneren2005/dsub/service/JukeboxService.java b/src/github/daneren2005/dsub/service/JukeboxService.java deleted file mode 100644 index c44b98c4..00000000 --- a/src/github/daneren2005/dsub/service/JukeboxService.java +++ /dev/null @@ -1,359 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service; - -import android.content.Context; -import android.os.Handler; -import android.util.Log; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ProgressBar; -import android.widget.Toast; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.JukeboxStatus; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.domain.RemoteControlState; -import github.daneren2005.dsub.service.parser.SubsonicRESTException; -import github.daneren2005.dsub.util.Util; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -/** - * Provides an asynchronous interface to the remote jukebox on the Subsonic server. - * - * @author Sindre Mehus - * @version $Id$ - */ -public class JukeboxService { - - private static final String TAG = JukeboxService.class.getSimpleName(); - private static final long STATUS_UPDATE_INTERVAL_SECONDS = 5L; - - private final Handler handler = new Handler(); - private final TaskQueue tasks = new TaskQueue(); - private final DownloadServiceImpl downloadService; - private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); - private ScheduledFuture statusUpdateFuture; - private final AtomicLong timeOfLastUpdate = new AtomicLong(); - private JukeboxStatus jukeboxStatus; - private float gain = 0.5f; - private VolumeToast volumeToast; - - // TODO: Report warning if queue fills up. - // TODO: Create shutdown method? - // TODO: Disable repeat. - // TODO: Persist RC state? - // TODO: Minimize status updates. - - public JukeboxService(DownloadServiceImpl downloadService) { - this.downloadService = downloadService; - new Thread() { - @Override - public void run() { - processTasks(); - } - }.start(); - } - - private synchronized void startStatusUpdate() { - stopStatusUpdate(); - Runnable updateTask = new Runnable() { - @Override - public void run() { - tasks.remove(GetStatus.class); - tasks.add(new GetStatus()); - } - }; - statusUpdateFuture = executorService.scheduleWithFixedDelay(updateTask, STATUS_UPDATE_INTERVAL_SECONDS, - STATUS_UPDATE_INTERVAL_SECONDS, TimeUnit.SECONDS); - } - - private synchronized void stopStatusUpdate() { - if (statusUpdateFuture != null) { - statusUpdateFuture.cancel(false); - statusUpdateFuture = null; - } - } - - private void processTasks() { - while (true) { - JukeboxTask task = null; - try { - task = tasks.take(); - JukeboxStatus status = task.execute(); - onStatusUpdate(status); - } catch (Throwable x) { - onError(task, x); - } - } - } - - private void onStatusUpdate(JukeboxStatus jukeboxStatus) { - timeOfLastUpdate.set(System.currentTimeMillis()); - this.jukeboxStatus = jukeboxStatus; - - // Track change? - Integer index = jukeboxStatus.getCurrentPlayingIndex(); - if (index != null && index != -1 && index != downloadService.getCurrentPlayingIndex()) { - downloadService.setPlayerState(PlayerState.COMPLETED); - downloadService.setCurrentPlaying(index, true); - downloadService.setPlayerState(PlayerState.STARTED); - } - } - - private void onError(JukeboxTask task, Throwable x) { - if (x instanceof ServerTooOldException && !(task instanceof Stop)) { - disableJukeboxOnError(x, R.string.download_jukebox_server_too_old); - } else if (x instanceof OfflineException && !(task instanceof Stop)) { - disableJukeboxOnError(x, R.string.download_jukebox_offline); - } else if (x instanceof SubsonicRESTException && ((SubsonicRESTException) x).getCode() == 50 && !(task instanceof Stop)) { - disableJukeboxOnError(x, R.string.download_jukebox_not_authorized); - } else { - Log.e(TAG, "Failed to process jukebox task: " + x, x); - } - } - - private void disableJukeboxOnError(Throwable x, final int resourceId) { - Log.w(TAG, x.toString()); - handler.post(new Runnable() { - @Override - public void run() { - Util.toast(downloadService, resourceId, false); - } - }); - downloadService.setRemoteEnabled(RemoteControlState.LOCAL); - } - - public void updatePlaylist() { - tasks.remove(Skip.class); - tasks.remove(Stop.class); - tasks.remove(Start.class); - - List ids = new ArrayList(); - for (DownloadFile file : downloadService.getDownloads()) { - ids.add(file.getSong().getId()); - } - tasks.add(new SetPlaylist(ids)); - } - - public void skip(final int index, final int offsetSeconds) { - tasks.remove(Skip.class); - tasks.remove(Stop.class); - tasks.remove(Start.class); - - startStatusUpdate(); - if (jukeboxStatus != null) { - jukeboxStatus.setPositionSeconds(offsetSeconds); - } - tasks.add(new Skip(index, offsetSeconds)); - downloadService.setPlayerState(PlayerState.STARTED); - } - - public void stop() { - tasks.remove(Stop.class); - tasks.remove(Start.class); - - stopStatusUpdate(); - tasks.add(new Stop()); - } - - public void start() { - tasks.remove(Stop.class); - tasks.remove(Start.class); - - startStatusUpdate(); - tasks.add(new Start()); - } - - public synchronized void adjustVolume(boolean up) { - float delta = up ? 0.1f : -0.1f; - gain += delta; - gain = Math.max(gain, 0.0f); - gain = Math.min(gain, 1.0f); - - tasks.remove(SetGain.class); - tasks.add(new SetGain(gain)); - - if (volumeToast == null) { - volumeToast = new VolumeToast(downloadService); - } - volumeToast.setVolume(gain); - } - - private MusicService getMusicService() { - return MusicServiceFactory.getMusicService(downloadService); - } - - public int getPositionSeconds() { - if (jukeboxStatus == null || jukeboxStatus.getPositionSeconds() == null || timeOfLastUpdate.get() == 0) { - return 0; - } - - if (jukeboxStatus.isPlaying()) { - int secondsSinceLastUpdate = (int) ((System.currentTimeMillis() - timeOfLastUpdate.get()) / 1000L); - return jukeboxStatus.getPositionSeconds() + secondsSinceLastUpdate; - } - - return jukeboxStatus.getPositionSeconds(); - } - - public void setEnabled(boolean enabled) { - tasks.clear(); - if (enabled) { - updatePlaylist(); - } - stop(); - downloadService.setPlayerState(PlayerState.IDLE); - } - - private static class TaskQueue { - - private final LinkedBlockingQueue queue = new LinkedBlockingQueue(); - - void add(JukeboxTask jukeboxTask) { - queue.add(jukeboxTask); - } - - JukeboxTask take() throws InterruptedException { - return queue.take(); - } - - void remove(Class clazz) { - try { - Iterator iterator = queue.iterator(); - while (iterator.hasNext()) { - JukeboxTask task = iterator.next(); - if (clazz.equals(task.getClass())) { - iterator.remove(); - } - } - } catch (Throwable x) { - Log.w(TAG, "Failed to clean-up task queue.", x); - } - } - - void clear() { - queue.clear(); - } - } - - private abstract class JukeboxTask { - - abstract JukeboxStatus execute() throws Exception; - - @Override - public String toString() { - return getClass().getSimpleName(); - } - } - - private class GetStatus extends JukeboxTask { - @Override - JukeboxStatus execute() throws Exception { - return getMusicService().getJukeboxStatus(downloadService, null); - } - } - - private class SetPlaylist extends JukeboxTask { - - private final List ids; - - SetPlaylist(List ids) { - this.ids = ids; - } - - @Override - JukeboxStatus execute() throws Exception { - return getMusicService().updateJukeboxPlaylist(ids, downloadService, null); - } - } - - private class Skip extends JukeboxTask { - private final int index; - private final int offsetSeconds; - - Skip(int index, int offsetSeconds) { - this.index = index; - this.offsetSeconds = offsetSeconds; - } - - @Override - JukeboxStatus execute() throws Exception { - return getMusicService().skipJukebox(index, offsetSeconds, downloadService, null); - } - } - - private class Stop extends JukeboxTask { - @Override - JukeboxStatus execute() throws Exception { - return getMusicService().stopJukebox(downloadService, null); - } - } - - private class Start extends JukeboxTask { - @Override - JukeboxStatus execute() throws Exception { - return getMusicService().startJukebox(downloadService, null); - } - } - - private class SetGain extends JukeboxTask { - - private final float gain; - - private SetGain(float gain) { - this.gain = gain; - } - - @Override - JukeboxStatus execute() throws Exception { - return getMusicService().setJukeboxGain(gain, downloadService, null); - } - } - - private static class VolumeToast extends Toast { - - private final ProgressBar progressBar; - - public VolumeToast(Context context) { - super(context); - setDuration(Toast.LENGTH_SHORT); - LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View view = inflater.inflate(R.layout.jukebox_volume, null); - progressBar = (ProgressBar) view.findViewById(R.id.jukebox_volume_progress_bar); - - setView(view); - setGravity(Gravity.TOP, 0, 0); - } - - public void setVolume(float volume) { - progressBar.setProgress(Math.round(100 * volume)); - show(); - } - } -} diff --git a/src/github/daneren2005/dsub/service/MusicService.java b/src/github/daneren2005/dsub/service/MusicService.java index 7aa878ab..cae307cb 100644 --- a/src/github/daneren2005/dsub/service/MusicService.java +++ b/src/github/daneren2005/dsub/service/MusicService.java @@ -27,13 +27,12 @@ import android.graphics.Bitmap; import github.daneren2005.dsub.domain.ChatMessage; import github.daneren2005.dsub.domain.Genre; import github.daneren2005.dsub.domain.Indexes; -import github.daneren2005.dsub.domain.JukeboxStatus; +import github.daneren2005.dsub.domain.RemoteStatus; import github.daneren2005.dsub.domain.Lyrics; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.MusicFolder; import github.daneren2005.dsub.domain.Playlist; import github.daneren2005.dsub.domain.PodcastChannel; -import github.daneren2005.dsub.domain.PodcastEpisode; import github.daneren2005.dsub.domain.SearchCritera; import github.daneren2005.dsub.domain.SearchResult; import github.daneren2005.dsub.domain.Share; @@ -98,17 +97,17 @@ public interface MusicService { String getHlsUrl(String id, int bitRate, Context context) throws Exception; - JukeboxStatus updateJukeboxPlaylist(List ids, Context context, ProgressListener progressListener) throws Exception; + RemoteStatus updateJukeboxPlaylist(List ids, Context context, ProgressListener progressListener) throws Exception; - JukeboxStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception; + RemoteStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception; - JukeboxStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception; + RemoteStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception; - JukeboxStatus startJukebox(Context context, ProgressListener progressListener) throws Exception; + RemoteStatus startJukebox(Context context, ProgressListener progressListener) throws Exception; - JukeboxStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception; + RemoteStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception; - JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception; + RemoteStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception; void setStarred(String id, boolean starred, Context context, ProgressListener progressListener) throws Exception; diff --git a/src/github/daneren2005/dsub/service/OfflineMusicService.java b/src/github/daneren2005/dsub/service/OfflineMusicService.java index 22fdcd9b..1221df5c 100644 --- a/src/github/daneren2005/dsub/service/OfflineMusicService.java +++ b/src/github/daneren2005/dsub/service/OfflineMusicService.java @@ -37,13 +37,12 @@ import android.util.Log; import github.daneren2005.dsub.domain.Artist; import github.daneren2005.dsub.domain.Genre; import github.daneren2005.dsub.domain.Indexes; -import github.daneren2005.dsub.domain.JukeboxStatus; +import github.daneren2005.dsub.domain.RemoteStatus; import github.daneren2005.dsub.domain.Lyrics; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.MusicFolder; import github.daneren2005.dsub.domain.Playlist; import github.daneren2005.dsub.domain.PodcastChannel; -import github.daneren2005.dsub.domain.PodcastEpisode; import github.daneren2005.dsub.domain.SearchCritera; import github.daneren2005.dsub.domain.SearchResult; import github.daneren2005.dsub.util.Constants; @@ -523,32 +522,32 @@ public class OfflineMusicService extends RESTMusicService { } @Override - public JukeboxStatus updateJukeboxPlaylist(List ids, Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus updateJukeboxPlaylist(List ids, Context context, ProgressListener progressListener) throws Exception { throw new OfflineException("Jukebox not available in offline mode"); } @Override - public JukeboxStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception { throw new OfflineException("Jukebox not available in offline mode"); } @Override - public JukeboxStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception { throw new OfflineException("Jukebox not available in offline mode"); } @Override - public JukeboxStatus startJukebox(Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus startJukebox(Context context, ProgressListener progressListener) throws Exception { throw new OfflineException("Jukebox not available in offline mode"); } @Override - public JukeboxStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception { throw new OfflineException("Jukebox not available in offline mode"); } @Override - public JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception { throw new OfflineException("Jukebox not available in offline mode"); } diff --git a/src/github/daneren2005/dsub/service/RESTMusicService.java b/src/github/daneren2005/dsub/service/RESTMusicService.java index 17f26ea1..82148dc0 100644 --- a/src/github/daneren2005/dsub/service/RESTMusicService.java +++ b/src/github/daneren2005/dsub/service/RESTMusicService.java @@ -22,9 +22,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.io.FileReader; import java.io.OutputStream; -import java.io.OutputStreamWriter; import java.io.Reader; import java.net.URLEncoder; import java.util.ArrayList; @@ -71,7 +69,6 @@ import android.net.NetworkInfo; import android.util.Log; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.*; -import github.daneren2005.dsub.domain.MusicDirectory.Entry; import github.daneren2005.dsub.service.parser.AlbumListParser; import github.daneren2005.dsub.service.parser.ChatMessageParser; import github.daneren2005.dsub.service.parser.ErrorParser; @@ -740,7 +737,7 @@ public class RESTMusicService implements MusicService { } @Override - public JukeboxStatus updateJukeboxPlaylist(List ids, Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus updateJukeboxPlaylist(List ids, Context context, ProgressListener progressListener) throws Exception { int n = ids.size(); List parameterNames = new ArrayList(n + 1); parameterNames.add("action"); @@ -755,36 +752,40 @@ public class RESTMusicService implements MusicService { } @Override - public JukeboxStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception { List parameterNames = Arrays.asList("action", "index", "offset"); List parameterValues = Arrays.asList("skip", index, offsetSeconds); + if(index < 0) { + parameterNames.remove(1); + parameterValues.remove(1); + } return executeJukeboxCommand(context, progressListener, parameterNames, parameterValues); } @Override - public JukeboxStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception { return executeJukeboxCommand(context, progressListener, Arrays.asList("action"), Arrays.asList("stop")); } @Override - public JukeboxStatus startJukebox(Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus startJukebox(Context context, ProgressListener progressListener) throws Exception { return executeJukeboxCommand(context, progressListener, Arrays.asList("action"), Arrays.asList("start")); } @Override - public JukeboxStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception { return executeJukeboxCommand(context, progressListener, Arrays.asList("action"), Arrays.asList("status")); } @Override - public JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception { + public RemoteStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception { List parameterNames = Arrays.asList("action", "gain"); List parameterValues = Arrays.asList("setGain", gain); return executeJukeboxCommand(context, progressListener, parameterNames, parameterValues); } - private JukeboxStatus executeJukeboxCommand(Context context, ProgressListener progressListener, List parameterNames, List parameterValues) throws Exception { + private RemoteStatus executeJukeboxCommand(Context context, ProgressListener progressListener, List parameterNames, List parameterValues) throws Exception { checkServerVersion(context, "1.7", "Jukebox not supported."); Reader reader = getReader(context, progressListener, "jukeboxControl", null, parameterNames, parameterValues); try { diff --git a/src/github/daneren2005/dsub/service/RemoteController.java b/src/github/daneren2005/dsub/service/RemoteController.java index 717c2c72..f2b8f20d 100644 --- a/src/github/daneren2005/dsub/service/RemoteController.java +++ b/src/github/daneren2005/dsub/service/RemoteController.java @@ -20,19 +20,27 @@ package github.daneren2005.dsub.service; import android.content.Context; +import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.widget.ProgressBar; import android.widget.Toast; + +import java.util.Iterator; +import java.util.concurrent.LinkedBlockingQueue; + import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.RemoteStatus; public abstract class RemoteController { + private static final String TAG = RemoteController.class.getSimpleName(); protected DownloadServiceImpl downloadService; private VolumeToast volumeToast; - + public abstract void start(); public abstract void stop(); + public abstract void shutdown(); public abstract void updatePlaylist(); public abstract void changePosition(int seconds); @@ -40,6 +48,45 @@ public abstract class RemoteController { public abstract void setVolume(boolean up); public abstract int getRemotePosition(); + + protected abstract class RemoteTask { + abstract RemoteStatus execute() throws Exception; + + @Override + public String toString() { + return getClass().getSimpleName(); + } + } + + protected static class TaskQueue { + private final LinkedBlockingQueue queue = new LinkedBlockingQueue(); + + void add(RemoteTask jukeboxTask) { + queue.add(jukeboxTask); + } + + RemoteTask take() throws InterruptedException { + return queue.take(); + } + + void remove(Class clazz) { + try { + Iterator iterator = queue.iterator(); + while (iterator.hasNext()) { + RemoteTask task = iterator.next(); + if (clazz.equals(task.getClass())) { + iterator.remove(); + } + } + } catch (Throwable x) { + Log.w(TAG, "Failed to clean-up task queue.", x); + } + } + + void clear() { + queue.clear(); + } + } protected VolumeToast getVolumeToast() { if(volumeToast == null) { @@ -48,7 +95,7 @@ public abstract class RemoteController { return volumeToast; } - public static class VolumeToast extends Toast { + protected static class VolumeToast extends Toast { private final ProgressBar progressBar; public VolumeToast(Context context) { diff --git a/src/github/daneren2005/dsub/service/parser/JukeboxStatusParser.java b/src/github/daneren2005/dsub/service/parser/JukeboxStatusParser.java index 8526e635..b7fc2f3f 100644 --- a/src/github/daneren2005/dsub/service/parser/JukeboxStatusParser.java +++ b/src/github/daneren2005/dsub/service/parser/JukeboxStatusParser.java @@ -23,7 +23,7 @@ import java.io.Reader; import org.xmlpull.v1.XmlPullParser; import android.content.Context; -import github.daneren2005.dsub.domain.JukeboxStatus; +import github.daneren2005.dsub.domain.RemoteStatus; /** * @author Sindre Mehus @@ -34,11 +34,11 @@ public class JukeboxStatusParser extends AbstractParser { super(context); } - public JukeboxStatus parse(Reader reader) throws Exception { + public RemoteStatus parse(Reader reader) throws Exception { init(reader); - JukeboxStatus jukeboxStatus = new JukeboxStatus(); + RemoteStatus jukeboxStatus = new RemoteStatus(); int eventType; do { eventType = nextParseEvent(); -- cgit v1.2.3