diff --git a/README.md b/README.md
index 3232646..751db3c 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,10 @@ Android Support Library and [Cling](http://4thline.org/projects/cling/) are requ
Binaries for Cling are included in the libs folder.
+## Icons
+
+All icons are taken from the Android project.
+
## License
[BSD 3-Clause License](LICENSE.md)
\ No newline at end of file
diff --git a/res/drawable-hdpi/ic_action_next.png b/res/drawable-hdpi/ic_action_next.png
new file mode 100644
index 0000000..71076e4
Binary files /dev/null and b/res/drawable-hdpi/ic_action_next.png differ
diff --git a/res/drawable-hdpi/ic_action_pause.png b/res/drawable-hdpi/ic_action_pause.png
new file mode 100644
index 0000000..535ad58
Binary files /dev/null and b/res/drawable-hdpi/ic_action_pause.png differ
diff --git a/res/drawable-hdpi/ic_action_play.png b/res/drawable-hdpi/ic_action_play.png
new file mode 100644
index 0000000..e22b099
Binary files /dev/null and b/res/drawable-hdpi/ic_action_play.png differ
diff --git a/res/drawable-hdpi/ic_action_previous.png b/res/drawable-hdpi/ic_action_previous.png
new file mode 100644
index 0000000..c766ece
Binary files /dev/null and b/res/drawable-hdpi/ic_action_previous.png differ
diff --git a/res/drawable-hdpi/ic_action_repeat.png b/res/drawable-hdpi/ic_action_repeat.png
new file mode 100644
index 0000000..773e2de
Binary files /dev/null and b/res/drawable-hdpi/ic_action_repeat.png differ
diff --git a/res/drawable-hdpi/ic_action_shuffle.png b/res/drawable-hdpi/ic_action_shuffle.png
new file mode 100644
index 0000000..7387b59
Binary files /dev/null and b/res/drawable-hdpi/ic_action_shuffle.png differ
diff --git a/res/drawable-hdpi/ic_media_next.png b/res/drawable-hdpi/ic_media_next.png
deleted file mode 100644
index 6e27b81..0000000
Binary files a/res/drawable-hdpi/ic_media_next.png and /dev/null differ
diff --git a/res/drawable-hdpi/ic_media_pause.png b/res/drawable-hdpi/ic_media_pause.png
deleted file mode 100644
index 1d465a4..0000000
Binary files a/res/drawable-hdpi/ic_media_pause.png and /dev/null differ
diff --git a/res/drawable-hdpi/ic_media_play.png b/res/drawable-hdpi/ic_media_play.png
deleted file mode 100644
index 2746d17..0000000
Binary files a/res/drawable-hdpi/ic_media_play.png and /dev/null differ
diff --git a/res/drawable-hdpi/ic_media_previous.png b/res/drawable-hdpi/ic_media_previous.png
deleted file mode 100644
index 85b3766..0000000
Binary files a/res/drawable-hdpi/ic_media_previous.png and /dev/null differ
diff --git a/res/drawable-mdpi/ic_action_next.png b/res/drawable-mdpi/ic_action_next.png
new file mode 100644
index 0000000..5c66996
Binary files /dev/null and b/res/drawable-mdpi/ic_action_next.png differ
diff --git a/res/drawable-mdpi/ic_action_pause.png b/res/drawable-mdpi/ic_action_pause.png
new file mode 100644
index 0000000..95a39ff
Binary files /dev/null and b/res/drawable-mdpi/ic_action_pause.png differ
diff --git a/res/drawable-mdpi/ic_action_play.png b/res/drawable-mdpi/ic_action_play.png
new file mode 100644
index 0000000..b94fbe6
Binary files /dev/null and b/res/drawable-mdpi/ic_action_play.png differ
diff --git a/res/drawable-mdpi/ic_action_previous.png b/res/drawable-mdpi/ic_action_previous.png
new file mode 100644
index 0000000..c84e6b1
Binary files /dev/null and b/res/drawable-mdpi/ic_action_previous.png differ
diff --git a/res/drawable-mdpi/ic_action_repeat.png b/res/drawable-mdpi/ic_action_repeat.png
new file mode 100644
index 0000000..a2e8ec5
Binary files /dev/null and b/res/drawable-mdpi/ic_action_repeat.png differ
diff --git a/res/drawable-mdpi/ic_action_shuffle.png b/res/drawable-mdpi/ic_action_shuffle.png
new file mode 100644
index 0000000..e605c9c
Binary files /dev/null and b/res/drawable-mdpi/ic_action_shuffle.png differ
diff --git a/res/drawable-mdpi/ic_media_next.png b/res/drawable-mdpi/ic_media_next.png
deleted file mode 100644
index fcd73d9..0000000
Binary files a/res/drawable-mdpi/ic_media_next.png and /dev/null differ
diff --git a/res/drawable-mdpi/ic_media_pause.png b/res/drawable-mdpi/ic_media_pause.png
deleted file mode 100644
index 3e6b2a1..0000000
Binary files a/res/drawable-mdpi/ic_media_pause.png and /dev/null differ
diff --git a/res/drawable-mdpi/ic_media_play.png b/res/drawable-mdpi/ic_media_play.png
deleted file mode 100644
index 7966bbc..0000000
Binary files a/res/drawable-mdpi/ic_media_play.png and /dev/null differ
diff --git a/res/drawable-mdpi/ic_media_previous.png b/res/drawable-mdpi/ic_media_previous.png
deleted file mode 100644
index b653d05..0000000
Binary files a/res/drawable-mdpi/ic_media_previous.png and /dev/null differ
diff --git a/res/drawable-xhdpi/ic_action_next.png b/res/drawable-xhdpi/ic_action_next.png
new file mode 100644
index 0000000..5c030cb
Binary files /dev/null and b/res/drawable-xhdpi/ic_action_next.png differ
diff --git a/res/drawable-xhdpi/ic_action_pause.png b/res/drawable-xhdpi/ic_action_pause.png
new file mode 100644
index 0000000..b02cf90
Binary files /dev/null and b/res/drawable-xhdpi/ic_action_pause.png differ
diff --git a/res/drawable-xhdpi/ic_action_play.png b/res/drawable-xhdpi/ic_action_play.png
new file mode 100644
index 0000000..e01a844
Binary files /dev/null and b/res/drawable-xhdpi/ic_action_play.png differ
diff --git a/res/drawable-xhdpi/ic_action_previous.png b/res/drawable-xhdpi/ic_action_previous.png
new file mode 100644
index 0000000..f6eea80
Binary files /dev/null and b/res/drawable-xhdpi/ic_action_previous.png differ
diff --git a/res/drawable-xhdpi/ic_action_repeat.png b/res/drawable-xhdpi/ic_action_repeat.png
new file mode 100644
index 0000000..61dce04
Binary files /dev/null and b/res/drawable-xhdpi/ic_action_repeat.png differ
diff --git a/res/drawable-xhdpi/ic_action_shuffle.png b/res/drawable-xhdpi/ic_action_shuffle.png
new file mode 100644
index 0000000..b67295f
Binary files /dev/null and b/res/drawable-xhdpi/ic_action_shuffle.png differ
diff --git a/res/drawable-xhdpi/ic_media_next.png b/res/drawable-xhdpi/ic_media_next.png
deleted file mode 100644
index 4def965..0000000
Binary files a/res/drawable-xhdpi/ic_media_next.png and /dev/null differ
diff --git a/res/drawable-xhdpi/ic_media_pause.png b/res/drawable-xhdpi/ic_media_pause.png
deleted file mode 100644
index 6bd3d48..0000000
Binary files a/res/drawable-xhdpi/ic_media_pause.png and /dev/null differ
diff --git a/res/drawable-xhdpi/ic_media_play.png b/res/drawable-xhdpi/ic_media_play.png
deleted file mode 100644
index ccfef18..0000000
Binary files a/res/drawable-xhdpi/ic_media_play.png and /dev/null differ
diff --git a/res/drawable-xhdpi/ic_media_previous.png b/res/drawable-xhdpi/ic_media_previous.png
deleted file mode 100644
index c4472ae..0000000
Binary files a/res/drawable-xhdpi/ic_media_previous.png and /dev/null differ
diff --git a/res/drawable-xxhdpi/ic_action_next.png b/res/drawable-xxhdpi/ic_action_next.png
new file mode 100644
index 0000000..3c93772
Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_next.png differ
diff --git a/res/drawable-xxhdpi/ic_action_pause.png b/res/drawable-xxhdpi/ic_action_pause.png
new file mode 100644
index 0000000..293f712
Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_pause.png differ
diff --git a/res/drawable-xxhdpi/ic_action_play.png b/res/drawable-xxhdpi/ic_action_play.png
new file mode 100644
index 0000000..97ff9b0
Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_play.png differ
diff --git a/res/drawable-xxhdpi/ic_action_previous.png b/res/drawable-xxhdpi/ic_action_previous.png
new file mode 100644
index 0000000..99d6a79
Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_previous.png differ
diff --git a/res/drawable-xxhdpi/ic_action_repeat.png b/res/drawable-xxhdpi/ic_action_repeat.png
new file mode 100644
index 0000000..c46ffa9
Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_repeat.png differ
diff --git a/res/drawable-xxhdpi/ic_action_shuffle.png b/res/drawable-xxhdpi/ic_action_shuffle.png
new file mode 100644
index 0000000..a2e1785
Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_shuffle.png differ
diff --git a/res/layout/route_fragment.xml b/res/layout/route_fragment.xml
index 9682fab..025820e 100644
--- a/res/layout/route_fragment.xml
+++ b/res/layout/route_fragment.xml
@@ -50,6 +50,13 @@
android:layout_alignParentTop="true"
android:gravity="right"
android:minEms="2" />
+
+
+
+
#BB99CC00
+ #ff33b5e5
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3dad884..6a359ea 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -9,6 +9,8 @@
Do you really want to exit the renderer? Playback will be stopped.
Previous
Next
+ Shuffle
+ Repeat
Please select a route
Album Art
DLNA Playback
diff --git a/src/com/github/nutomic/controldlna/gui/RouteFragment.java b/src/com/github/nutomic/controldlna/gui/RouteFragment.java
index aaa2db6..5ac8277 100644
--- a/src/com/github/nutomic/controldlna/gui/RouteFragment.java
+++ b/src/com/github/nutomic/controldlna/gui/RouteFragment.java
@@ -86,6 +86,8 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements
private View mControls;
private SeekBar mProgressBar;
private ImageButton mPlayPause;
+ private ImageButton mShuffle;
+ private ImageButton mRepeat;
private View mCurrentTrackView;
@@ -111,6 +113,7 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements
mMediaRouterPlayService.getService().setRouterFragment(RouteFragment.this);
mPlaylistAdapter.addAll(mMediaRouterPlayService.getService().getPlaylist());
receiveIsPlaying(mMediaRouterPlayService.getService().getCurrentTrack());
+ applyColors();
}
public void onServiceDisconnected(ComponentName className) {
@@ -157,17 +160,25 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements
mProgressBar = (SeekBar) getView().findViewById(R.id.progressBar);
mProgressBar.setOnSeekBarChangeListener(this);
+ mShuffle = (ImageButton) getView().findViewById(R.id.shuffle);
+ mShuffle.setImageResource(R.drawable.ic_action_shuffle);
+ mShuffle.setOnClickListener(this);
+
ImageButton previous = (ImageButton) getView().findViewById(R.id.previous);
- previous.setImageResource(R.drawable.ic_media_previous);
- getView().findViewById(R.id.previous).setOnClickListener(this);
+ previous.setImageResource(R.drawable.ic_action_previous);
+ previous.setOnClickListener(this);
ImageButton next = (ImageButton) getView().findViewById(R.id.next);
- next.setImageResource(R.drawable.ic_media_next);
- getView().findViewById(R.id.next).setOnClickListener(this);
+ next.setImageResource(R.drawable.ic_action_next);
+ next.setOnClickListener(this);
+
+ mRepeat = (ImageButton) getView().findViewById(R.id.repeat);
+ mRepeat.setImageResource(R.drawable.ic_action_repeat);
+ mRepeat.setOnClickListener(this);
mPlayPause = (ImageButton) getView().findViewById(R.id.playpause);
mPlayPause.setOnClickListener(this);
- mPlayPause.setImageResource(R.drawable.ic_media_play);
+ mPlayPause.setImageResource(R.drawable.ic_action_play);
getActivity().getApplicationContext().startService(
new Intent(getActivity(), MediaRouterPlayService.class));
@@ -361,21 +372,47 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements
*/
@Override
public void onClick(View v) {
+ MediaRouterPlayService s = mMediaRouterPlayService.getService();
switch (v.getId()) {
case R.id.playpause:
if (mPlaying)
- mMediaRouterPlayService.getService().pause();
+ s.pause();
else
- mMediaRouterPlayService.getService().resume();
+ s.resume();
+ break;
+ case R.id.shuffle:
+ s.toggleShuffleEnabled();
+ applyColors();
break;
case R.id.previous:
- mMediaRouterPlayService.getService().playPrevious();
+ s.playPrevious();
break;
case R.id.next:
- mMediaRouterPlayService.getService().playNext();
+ s.playNext();
+ break;
+ case R.id.repeat:
+ s.toggleRepeatEnabled();
+ applyColors();
break;
}
}
+
+ /**
+ * Enables or disables highlighting on shuffle/repeat buttons (depending
+ * if they are enabled or disabled).
+ */
+ private void applyColors() {
+ MediaRouterPlayService s = mMediaRouterPlayService.getService();
+ int highlight = getResources().getColor(R.color.button_highlight);
+ int transparent = getResources().getColor(android.R.color.transparent);
+
+ mShuffle.setColorFilter((s.getShuffleEnabled())
+ ? highlight
+ : transparent);
+ mRepeat.setColorFilter((s.getRepeatEnabled())
+ ? highlight
+ : transparent);
+ }
/**
* Sends manual seek on progress bar to renderer.
@@ -484,11 +521,11 @@ public class RouteFragment extends MediaRouteDiscoveryFragment implements
status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_BUFFERING ||
status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_PENDING) {
mPlaying = true;
- mPlayPause.setImageResource(R.drawable.ic_media_pause);
+ mPlayPause.setImageResource(R.drawable.ic_action_pause);
}
else {
mPlaying = false;
- mPlayPause.setImageResource(R.drawable.ic_media_play);
+ mPlayPause.setImageResource(R.drawable.ic_action_play);
}
if (mListView.getAdapter() == mPlaylistAdapter)
diff --git a/src/com/github/nutomic/controldlna/mediarouter/MediaRouterPlayService.java b/src/com/github/nutomic/controldlna/mediarouter/MediaRouterPlayService.java
index ee39d52..b05ffcc 100644
--- a/src/com/github/nutomic/controldlna/mediarouter/MediaRouterPlayService.java
+++ b/src/com/github/nutomic/controldlna/mediarouter/MediaRouterPlayService.java
@@ -30,6 +30,7 @@ package com.github.nutomic.controldlna.mediarouter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
+import java.util.Random;
import org.teleal.cling.support.contentdirectory.DIDLParser;
import org.teleal.cling.support.model.DIDLContent;
@@ -86,6 +87,10 @@ public class MediaRouterPlayService extends Service {
*/
private int mCurrentTrack = -1;
+ private boolean mShuffle = false;
+
+ private boolean mRepeat = false;
+
private String mItemId;
private String mSessionId;
@@ -243,6 +248,9 @@ public class MediaRouterPlayService extends Service {
* Sends 'pause' signal to current renderer.
*/
public void pause() {
+ if (mPlaylist.isEmpty())
+ return;
+
Intent intent = new Intent(MediaControlIntent.ACTION_PAUSE);
intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, mSessionId);
@@ -253,6 +261,9 @@ public class MediaRouterPlayService extends Service {
* Sends 'resume' signal to current renderer.
*/
public void resume() {
+ if (mPlaylist.isEmpty())
+ return;
+
Intent intent = new Intent(MediaControlIntent.ACTION_RESUME);
intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, mSessionId);
@@ -267,6 +278,9 @@ public class MediaRouterPlayService extends Service {
* Sends 'stop' signal to current renderer.
*/
public void stop() {
+ if (mPlaylist.isEmpty())
+ return;
+
Intent intent = new Intent(MediaControlIntent.ACTION_STOP);
intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, mSessionId);
@@ -274,6 +288,9 @@ public class MediaRouterPlayService extends Service {
}
public void seek(int seconds) {
+ if (mPlaylist.isEmpty())
+ return;
+
Intent intent = new Intent(MediaControlIntent.ACTION_SEEK);
intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, mSessionId);
@@ -296,7 +313,23 @@ public class MediaRouterPlayService extends Service {
* Plays the track after current in the playlist.
*/
public void playNext() {
- play(mCurrentTrack + 1);
+ if (mCurrentTrack == -1)
+ return;
+
+ if (mShuffle)
+ // Play random item.
+ play(new Random().nextInt(mPlaylist.size()));
+ else if (mCurrentTrack + 1 < mPlaylist.size())
+ // Playlist not over, play next item.
+ play(mCurrentTrack + 1);
+ else if (mRepeat)
+ // Playlist over, repeat it.
+ play(0);
+ else if (!mBound) {
+ // Playlist over, stop playback.
+ stopSelf();
+ mPollingStatus = false;
+ }
}
@@ -304,7 +337,14 @@ public class MediaRouterPlayService extends Service {
* Plays the track before current in the playlist.
*/
public void playPrevious() {
- play(mCurrentTrack - 1);
+ if (mCurrentTrack == -1)
+ return;
+
+ if (mShuffle)
+ // Play random item.
+ play(new Random().nextInt(mPlaylist.size()));
+ else
+ play(mCurrentTrack - 1);
}
/**
@@ -339,15 +379,8 @@ public class MediaRouterPlayService extends Service {
status.getPlaybackState() != MediaItemStatus.PLAYBACK_STATE_PLAYING)
stopForeground(true);
- if (status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_FINISHED) {
- if (mCurrentTrack + 1 < mPlaylist.size())
- playNext();
- else {
- if (!mBound)
- stopSelf();
- mPollingStatus = false;
- }
- }
+ if (status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_FINISHED)
+ playNext();
}
});
}
@@ -372,5 +405,21 @@ public class MediaRouterPlayService extends Service {
public List- getPlaylist() {
return mPlaylist;
}
+
+ public void toggleShuffleEnabled() {
+ mShuffle = !mShuffle;
+ }
+
+ public boolean getShuffleEnabled() {
+ return mShuffle;
+ }
+
+ public void toggleRepeatEnabled() {
+ mRepeat = !mRepeat;
+ }
+
+ public boolean getRepeatEnabled() {
+ return mRepeat;
+ }
}