aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Jackson <daneren2005@gmail.com>2016-04-06 16:59:30 -0700
committerScott Jackson <daneren2005@gmail.com>2016-04-06 16:59:30 -0700
commit8e2ee0646bfe61361081c584b9fcb49f1edb946f (patch)
tree01a6e903f84c53b863e950282f7f0671c40d472a
parenta5c45e631cbca4fd8e78d7ddc02ce1c19b973f50 (diff)
downloaddsub-8e2ee0646bfe61361081c584b9fcb49f1edb946f.tar.gz
dsub-8e2ee0646bfe61361081c584b9fcb49f1edb946f.tar.bz2
dsub-8e2ee0646bfe61361081c584b9fcb49f1edb946f.zip
#669 On Audio Books/Podcasts replace back/forward with rewind/fast forward
-rw-r--r--app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java58
-rw-r--r--app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java65
-rw-r--r--app/src/main/java/github/daneren2005/dsub/service/DownloadService.java21
-rw-r--r--app/src/main/java/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java6
-rw-r--r--app/src/main/java/github/daneren2005/dsub/util/Notifications.java52
-rw-r--r--app/src/main/res/drawable-hdpi/media_fastforward_dark.pngbin0 -> 1123 bytes
-rw-r--r--app/src/main/res/drawable-hdpi/media_fastforward_light.pngbin0 -> 1309 bytes
-rw-r--r--app/src/main/res/drawable-hdpi/media_rewind_dark.pngbin0 -> 1172 bytes
-rw-r--r--app/src/main/res/drawable-hdpi/media_rewind_light.pngbin0 -> 1286 bytes
-rw-r--r--app/src/main/res/drawable-mdpi/media_fastforward_dark.pngbin0 -> 654 bytes
-rw-r--r--app/src/main/res/drawable-mdpi/media_fastforward_light.pngbin0 -> 727 bytes
-rw-r--r--app/src/main/res/drawable-mdpi/media_rewind_dark.pngbin0 -> 660 bytes
-rw-r--r--app/src/main/res/drawable-mdpi/media_rewind_light.pngbin0 -> 707 bytes
-rw-r--r--app/src/main/res/drawable-v21/notification_fastforward.xml4
-rw-r--r--app/src/main/res/drawable-v21/notification_rewind.xml4
-rw-r--r--app/src/main/res/drawable-xhdpi/media_fastforward_dark.pngbin0 -> 1622 bytes
-rw-r--r--app/src/main/res/drawable-xhdpi/media_fastforward_light.pngbin0 -> 1847 bytes
-rw-r--r--app/src/main/res/drawable-xhdpi/media_rewind_dark.pngbin0 -> 1542 bytes
-rw-r--r--app/src/main/res/drawable-xhdpi/media_rewind_light.pngbin0 -> 1697 bytes
-rw-r--r--app/src/main/res/drawable-xxhdpi/media_fastforward_dark.pngbin0 -> 2837 bytes
-rw-r--r--app/src/main/res/drawable-xxhdpi/media_fastforward_light.pngbin0 -> 3139 bytes
-rw-r--r--app/src/main/res/drawable-xxhdpi/media_rewind_dark.pngbin0 -> 3007 bytes
-rw-r--r--app/src/main/res/drawable-xxhdpi/media_rewind_light.pngbin0 -> 3243 bytes
-rw-r--r--app/src/main/res/drawable-xxxhdpi/media_fastforward_dark.pngbin0 -> 4784 bytes
-rw-r--r--app/src/main/res/drawable-xxxhdpi/media_fastforward_light.pngbin0 -> 5304 bytes
-rw-r--r--app/src/main/res/drawable-xxxhdpi/media_rewind_dark.pngbin0 -> 4993 bytes
-rw-r--r--app/src/main/res/drawable-xxxhdpi/media_rewind_light.pngbin0 -> 5407 bytes
-rw-r--r--app/src/main/res/drawable/notification_fastforward.xml4
-rw-r--r--app/src/main/res/drawable/notification_rewind.xml4
-rw-r--r--app/src/main/res/layout/abstract_fragment_activity.xml14
-rw-r--r--app/src/main/res/layout/download_media_buttons.xml16
-rw-r--r--app/src/main/res/values/attrs.xml4
-rw-r--r--app/src/main/res/values/themes.xml10
33 files changed, 239 insertions, 23 deletions
diff --git a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java
index 487ad83c..8273f61c 100644
--- a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java
+++ b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java
@@ -107,6 +107,10 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
private long lastBackPressTime = 0;
private DownloadFile currentPlaying;
private PlayerState currentState;
+ private ImageButton previousButton;
+ private ImageButton nextButton;
+ private ImageButton rewindButton;
+ private ImageButton fastforwardButton;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -267,7 +271,25 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
trans.commit();
}
- ImageButton previousButton = (ImageButton) findViewById(R.id.download_previous);
+ rewindButton = (ImageButton) findViewById(R.id.download_rewind);
+ rewindButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ if (getDownloadService() == null) {
+ return null;
+ }
+
+ getDownloadService().rewind();
+ return null;
+ }
+ }.execute();
+ }
+ });
+
+ previousButton = (ImageButton) findViewById(R.id.download_previous);
previousButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -305,7 +327,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
}
});
- ImageButton nextButton = (ImageButton) findViewById(R.id.download_next);
+ nextButton = (ImageButton) findViewById(R.id.download_next);
nextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -322,6 +344,24 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
}.execute();
}
});
+
+ fastforwardButton = (ImageButton) findViewById(R.id.download_fastforward);
+ fastforwardButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ if (getDownloadService() == null) {
+ return null;
+ }
+
+ getDownloadService().fastForward();
+ return null;
+ }
+ }.execute();
+ }
+ });
}
@Override
@@ -875,6 +915,20 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
}
getImageLoader().loadImage(coverArtView, song, false, height, false);
}
+
+ if(currentPlaying != null && currentPlaying.getSong() != null && (currentPlaying.getSong().isPodcast() || currentPlaying.getSong().isAudioBook())) {
+ previousButton.setVisibility(View.GONE);
+ nextButton.setVisibility(View.GONE);
+
+ rewindButton.setVisibility(View.VISIBLE);
+ fastforwardButton.setVisibility(View.VISIBLE);
+ } else {
+ previousButton.setVisibility(View.VISIBLE);
+ nextButton.setVisibility(View.VISIBLE);
+
+ rewindButton.setVisibility(View.GONE);
+ fastforwardButton.setVisibility(View.GONE);
+ }
}
@Override
diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java
index 9bca096b..c8e99f51 100644
--- a/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java
+++ b/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java
@@ -88,7 +88,6 @@ import java.util.concurrent.ScheduledFuture;
public class NowPlayingFragment extends SubsonicFragment implements OnGestureListener, SectionAdapter.OnItemClickedListener<DownloadFile>, OnSongChangedListener {
private static final String TAG = NowPlayingFragment.class.getSimpleName();
private static final int PERCENTAGE_OF_SCREEN_FOR_SWIPE = 10;
- private static final int INCREMENT_TIME = 5000;
private static final int ACTION_PREVIOUS = 1;
private static final int ACTION_NEXT = 2;
@@ -106,6 +105,8 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
private SeekBar progressBar;
private AutoRepeatButton previousButton;
private AutoRepeatButton nextButton;
+ private AutoRepeatButton rewindButton;
+ private AutoRepeatButton fastforwardButton;
private View pauseButton;
private View stopButton;
private View startButton;
@@ -172,6 +173,8 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
progressBar = (SeekBar)rootView.findViewById(R.id.download_progress_bar);
previousButton = (AutoRepeatButton)rootView.findViewById(R.id.download_previous);
nextButton = (AutoRepeatButton)rootView.findViewById(R.id.download_next);
+ rewindButton = (AutoRepeatButton) rootView.findViewById(R.id.download_rewind);
+ fastforwardButton = (AutoRepeatButton) rootView.findViewById(R.id.download_fastforward);
pauseButton =rootView.findViewById(R.id.download_pause);
stopButton =rootView.findViewById(R.id.download_stop);
startButton =rootView.findViewById(R.id.download_start);
@@ -240,7 +243,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
});
previousButton.setOnRepeatListener(new Runnable() {
public void run() {
- changeProgress(-INCREMENT_TIME);
+ changeProgress(true);
}
});
@@ -260,10 +263,35 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
});
nextButton.setOnRepeatListener(new Runnable() {
public void run() {
- changeProgress(INCREMENT_TIME);
+ changeProgress(false);
}
});
+ rewindButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ changeProgress(true);
+ }
+ });
+ rewindButton.setOnRepeatListener(new Runnable() {
+ public void run() {
+ changeProgress(true);
+ }
+ });
+
+ fastforwardButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ changeProgress(false);
+ }
+ });
+ fastforwardButton.setOnRepeatListener(new Runnable() {
+ public void run() {
+ changeProgress(false);
+ }
+ });
+
+
pauseButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
@@ -948,31 +976,22 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
}
}
- private void changeProgress(final int ms) {
+ private void changeProgress(final boolean rewind) {
final DownloadService downloadService = getDownloadService();
if(downloadService == null) {
return;
}
new SilentBackgroundTask<Void>(context) {
- boolean isJukeboxEnabled;
- int msPlayed;
- Integer duration;
- PlayerState playerState;
int seekTo;
@Override
protected Void doInBackground() throws Throwable {
- msPlayed = Math.max(0, downloadService.getPlayerPosition());
- duration = downloadService.getPlayerDuration();
- playerState = getDownloadService().getPlayerState();
- int msTotal = duration == null ? 0 : duration;
- if(msPlayed + ms > msTotal) {
- seekTo = msTotal;
+ if(rewind) {
+ seekTo = downloadService.rewind();
} else {
- seekTo = msPlayed + ms;
+ seekTo = downloadService.fastForward();
}
- downloadService.seekTo(seekTo);
return null;
}
@@ -1169,6 +1188,20 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
public void onSongChanged(DownloadFile currentPlaying, int currentPlayingIndex) {
this.currentPlaying = currentPlaying;
setupSubtitle(currentPlayingIndex);
+
+ if(currentPlaying != null && currentPlaying.getSong() != null && (currentPlaying.getSong().isPodcast() || currentPlaying.getSong().isAudioBook())) {
+ previousButton.setVisibility(View.GONE);
+ nextButton.setVisibility(View.GONE);
+
+ rewindButton.setVisibility(View.VISIBLE);
+ fastforwardButton.setVisibility(View.VISIBLE);
+ } else {
+ previousButton.setVisibility(View.VISIBLE);
+ nextButton.setVisibility(View.VISIBLE);
+
+ rewindButton.setVisibility(View.GONE);
+ fastforwardButton.setVisibility(View.GONE);
+ }
}
private void setupSubtitle(int currentPlayingIndex) {
diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java
index 2d46c1d4..01007b68 100644
--- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java
+++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java
@@ -1131,6 +1131,27 @@ public class DownloadService extends Service {
handleError(x);
}
}
+ public synchronized int rewind() {
+ return seekToWrapper(-REWIND);
+ }
+ public synchronized int fastForward() {
+ return seekToWrapper(FAST_FORWARD);
+ }
+ protected int seekToWrapper(int difference) {
+ int msPlayed = Math.max(0, getPlayerPosition());
+ Integer duration = getPlayerDuration();
+ int msTotal = duration == null ? 0 : duration;
+
+ int seekTo;
+ if(msPlayed + difference > msTotal) {
+ seekTo = msTotal;
+ } else {
+ seekTo = msPlayed + difference;
+ }
+ seekTo(seekTo);
+
+ return seekTo;
+ }
public synchronized void previous() {
int index = getCurrentPlayingIndex();
diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java
index fe75e248..8c61464f 100644
--- a/app/src/main/java/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java
+++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java
@@ -408,6 +408,12 @@ public class DownloadServiceLifecycleSupport {
case KeyEvent.KEYCODE_MEDIA_NEXT:
downloadService.next();
break;
+ case KeyEvent.KEYCODE_MEDIA_REWIND:
+ downloadService.rewind();
+ break;
+ case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+ downloadService.fastForward();
+ break;
case RemoteControlClient.FLAG_KEY_MEDIA_STOP:
case KeyEvent.KEYCODE_MEDIA_STOP:
downloadService.stop();
diff --git a/app/src/main/java/github/daneren2005/dsub/util/Notifications.java b/app/src/main/java/github/daneren2005/dsub/util/Notifications.java
index a59a9766..e4f9edeb 100644
--- a/app/src/main/java/github/daneren2005/dsub/util/Notifications.java
+++ b/app/src/main/java/github/daneren2005/dsub/util/Notifications.java
@@ -104,7 +104,7 @@ public final class Notifications {
handler.post(new Runnable() {
@Override
public void run() {
- if(playing) {
+ if (playing) {
downloadService.startForeground(NOTIFICATION_ID_PLAYING, notification);
} else {
playShowing = false;
@@ -121,7 +121,8 @@ public final class Notifications {
DSubWidgetProvider.notifyInstances(context, downloadService, playing);
}
- private static void setupViews(RemoteViews rv, Context context, MusicDirectory.Entry song, boolean expanded, boolean playing, boolean remote){
+ private static void setupViews(RemoteViews rv, Context context, MusicDirectory.Entry song, boolean expanded, boolean playing, boolean remote) {
+ boolean isLongFile = song.isAudioBook() || song.isPodcast();
// Use the same text for the ticker and the expanded notification
String title = song.getTitle();
@@ -156,20 +157,47 @@ public final class Notifications {
if(persistent) {
if(expanded) {
rv.setImageViewResource(R.id.control_pause, playing ? R.drawable.notification_pause : R.drawable.notification_start);
+
+ if(isLongFile && playing) {
+ rv.setImageViewResource(R.id.control_previous, R.drawable.notification_rewind);
+ rv.setImageViewResource(R.id.control_next, R.drawable.notification_fastforward);
+ } else {
+ rv.setImageViewResource(R.id.control_previous, R.drawable.notification_backward);
+ rv.setImageViewResource(R.id.control_next, R.drawable.notification_forward);
+ }
} else {
rv.setImageViewResource(R.id.control_previous, playing ? R.drawable.notification_pause : R.drawable.notification_start);
- rv.setImageViewResource(R.id.control_pause, R.drawable.notification_forward);
+ if(isLongFile && playing) {
+ rv.setImageViewResource(R.id.control_pause, R.drawable.notification_fastforward);
+ } else {
+ rv.setImageViewResource(R.id.control_pause, R.drawable.notification_forward);
+ }
rv.setImageViewResource(R.id.control_next, R.drawable.notification_close);
}
+ } else if(isLongFile) {
+ rv.setImageViewResource(R.id.control_previous, R.drawable.notification_rewind);
+ rv.setImageViewResource(R.id.control_next, R.drawable.notification_fastforward);
+ } else {
+ // Necessary for switching back since it appears to re-use the same layout
+ rv.setImageViewResource(R.id.control_previous, R.drawable.notification_backward);
+ rv.setImageViewResource(R.id.control_next, R.drawable.notification_forward);
}
// Create actions for media buttons
PendingIntent pendingIntent;
- int previous = 0, pause = 0, next = 0, close = 0;
+ int previous = 0, pause = 0, next = 0, close = 0, rewind = 0, fastForward = 0;
if(persistent && !expanded) {
pause = R.id.control_previous;
- next = R.id.control_pause;
+ if(isLongFile && playing) {
+ fastForward = R.id.control_pause;
+ } else {
+ next = R.id.control_pause;
+ }
close = R.id.control_next;
+ } else if(isLongFile && (!persistent || (expanded && playing))) {
+ rewind = R.id.control_previous;
+ pause = R.id.control_pause;
+ fastForward = R.id.control_next;
} else {
previous = R.id.control_previous;
pause = R.id.control_pause;
@@ -188,6 +216,13 @@ public final class Notifications {
pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0);
rv.setOnClickPendingIntent(previous, pendingIntent);
}
+ if(rewind > 0) {
+ Intent rewindIntent = new Intent("KEYCODE_MEDIA_REWIND");
+ rewindIntent.setComponent(new ComponentName(context, DownloadService.class));
+ rewindIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_REWIND));
+ pendingIntent = PendingIntent.getService(context, 0, rewindIntent, 0);
+ rv.setOnClickPendingIntent(rewind, pendingIntent);
+ }
if(pause > 0) {
if(playing) {
Intent pauseIntent = new Intent("KEYCODE_MEDIA_PLAY_PAUSE");
@@ -210,6 +245,13 @@ public final class Notifications {
pendingIntent = PendingIntent.getService(context, 0, nextIntent, 0);
rv.setOnClickPendingIntent(next, pendingIntent);
}
+ if(fastForward > 0) {
+ Intent fastForwardIntent = new Intent("KEYCODE_MEDIA_FAST_FORWARD");
+ fastForwardIntent.setComponent(new ComponentName(context, DownloadService.class));
+ fastForwardIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD));
+ pendingIntent = PendingIntent.getService(context, 0, fastForwardIntent, 0);
+ rv.setOnClickPendingIntent(fastForward, pendingIntent);
+ }
if(close > 0) {
Intent prevIntent = new Intent("KEYCODE_MEDIA_STOP");
prevIntent.setComponent(new ComponentName(context, DownloadService.class));
diff --git a/app/src/main/res/drawable-hdpi/media_fastforward_dark.png b/app/src/main/res/drawable-hdpi/media_fastforward_dark.png
new file mode 100644
index 00000000..eab0cdfd
--- /dev/null
+++ b/app/src/main/res/drawable-hdpi/media_fastforward_dark.png
Binary files differ
diff --git a/app/src/main/res/drawable-hdpi/media_fastforward_light.png b/app/src/main/res/drawable-hdpi/media_fastforward_light.png
new file mode 100644
index 00000000..905faa9c
--- /dev/null
+++ b/app/src/main/res/drawable-hdpi/media_fastforward_light.png
Binary files differ
diff --git a/app/src/main/res/drawable-hdpi/media_rewind_dark.png b/app/src/main/res/drawable-hdpi/media_rewind_dark.png
new file mode 100644
index 00000000..5d2d62a7
--- /dev/null
+++ b/app/src/main/res/drawable-hdpi/media_rewind_dark.png
Binary files differ
diff --git a/app/src/main/res/drawable-hdpi/media_rewind_light.png b/app/src/main/res/drawable-hdpi/media_rewind_light.png
new file mode 100644
index 00000000..15bc91a8
--- /dev/null
+++ b/app/src/main/res/drawable-hdpi/media_rewind_light.png
Binary files differ
diff --git a/app/src/main/res/drawable-mdpi/media_fastforward_dark.png b/app/src/main/res/drawable-mdpi/media_fastforward_dark.png
new file mode 100644
index 00000000..f999e0b8
--- /dev/null
+++ b/app/src/main/res/drawable-mdpi/media_fastforward_dark.png
Binary files differ
diff --git a/app/src/main/res/drawable-mdpi/media_fastforward_light.png b/app/src/main/res/drawable-mdpi/media_fastforward_light.png
new file mode 100644
index 00000000..23107742
--- /dev/null
+++ b/app/src/main/res/drawable-mdpi/media_fastforward_light.png
Binary files differ
diff --git a/app/src/main/res/drawable-mdpi/media_rewind_dark.png b/app/src/main/res/drawable-mdpi/media_rewind_dark.png
new file mode 100644
index 00000000..2ecda48a
--- /dev/null
+++ b/app/src/main/res/drawable-mdpi/media_rewind_dark.png
Binary files differ
diff --git a/app/src/main/res/drawable-mdpi/media_rewind_light.png b/app/src/main/res/drawable-mdpi/media_rewind_light.png
new file mode 100644
index 00000000..f7c9b303
--- /dev/null
+++ b/app/src/main/res/drawable-mdpi/media_rewind_light.png
Binary files differ
diff --git a/app/src/main/res/drawable-v21/notification_fastforward.xml b/app/src/main/res/drawable-v21/notification_fastforward.xml
new file mode 100644
index 00000000..d0ab76a2
--- /dev/null
+++ b/app/src/main/res/drawable-v21/notification_fastforward.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<bitmap
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/media_fastforward_light"/> \ No newline at end of file
diff --git a/app/src/main/res/drawable-v21/notification_rewind.xml b/app/src/main/res/drawable-v21/notification_rewind.xml
new file mode 100644
index 00000000..25a16a02
--- /dev/null
+++ b/app/src/main/res/drawable-v21/notification_rewind.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<bitmap
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/media_rewind_light"/> \ No newline at end of file
diff --git a/app/src/main/res/drawable-xhdpi/media_fastforward_dark.png b/app/src/main/res/drawable-xhdpi/media_fastforward_dark.png
new file mode 100644
index 00000000..3c653286
--- /dev/null
+++ b/app/src/main/res/drawable-xhdpi/media_fastforward_dark.png
Binary files differ
diff --git a/app/src/main/res/drawable-xhdpi/media_fastforward_light.png b/app/src/main/res/drawable-xhdpi/media_fastforward_light.png
new file mode 100644
index 00000000..f105b458
--- /dev/null
+++ b/app/src/main/res/drawable-xhdpi/media_fastforward_light.png
Binary files differ
diff --git a/app/src/main/res/drawable-xhdpi/media_rewind_dark.png b/app/src/main/res/drawable-xhdpi/media_rewind_dark.png
new file mode 100644
index 00000000..08fdff06
--- /dev/null
+++ b/app/src/main/res/drawable-xhdpi/media_rewind_dark.png
Binary files differ
diff --git a/app/src/main/res/drawable-xhdpi/media_rewind_light.png b/app/src/main/res/drawable-xhdpi/media_rewind_light.png
new file mode 100644
index 00000000..3998f715
--- /dev/null
+++ b/app/src/main/res/drawable-xhdpi/media_rewind_light.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxhdpi/media_fastforward_dark.png b/app/src/main/res/drawable-xxhdpi/media_fastforward_dark.png
new file mode 100644
index 00000000..90f045ea
--- /dev/null
+++ b/app/src/main/res/drawable-xxhdpi/media_fastforward_dark.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxhdpi/media_fastforward_light.png b/app/src/main/res/drawable-xxhdpi/media_fastforward_light.png
new file mode 100644
index 00000000..73f0fba4
--- /dev/null
+++ b/app/src/main/res/drawable-xxhdpi/media_fastforward_light.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxhdpi/media_rewind_dark.png b/app/src/main/res/drawable-xxhdpi/media_rewind_dark.png
new file mode 100644
index 00000000..ff5bda9a
--- /dev/null
+++ b/app/src/main/res/drawable-xxhdpi/media_rewind_dark.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxhdpi/media_rewind_light.png b/app/src/main/res/drawable-xxhdpi/media_rewind_light.png
new file mode 100644
index 00000000..c50c0825
--- /dev/null
+++ b/app/src/main/res/drawable-xxhdpi/media_rewind_light.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxxhdpi/media_fastforward_dark.png b/app/src/main/res/drawable-xxxhdpi/media_fastforward_dark.png
new file mode 100644
index 00000000..63ac58e0
--- /dev/null
+++ b/app/src/main/res/drawable-xxxhdpi/media_fastforward_dark.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxxhdpi/media_fastforward_light.png b/app/src/main/res/drawable-xxxhdpi/media_fastforward_light.png
new file mode 100644
index 00000000..d2f7506b
--- /dev/null
+++ b/app/src/main/res/drawable-xxxhdpi/media_fastforward_light.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxxhdpi/media_rewind_dark.png b/app/src/main/res/drawable-xxxhdpi/media_rewind_dark.png
new file mode 100644
index 00000000..e911b342
--- /dev/null
+++ b/app/src/main/res/drawable-xxxhdpi/media_rewind_dark.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxxhdpi/media_rewind_light.png b/app/src/main/res/drawable-xxxhdpi/media_rewind_light.png
new file mode 100644
index 00000000..461118f1
--- /dev/null
+++ b/app/src/main/res/drawable-xxxhdpi/media_rewind_light.png
Binary files differ
diff --git a/app/src/main/res/drawable/notification_fastforward.xml b/app/src/main/res/drawable/notification_fastforward.xml
new file mode 100644
index 00000000..355c6a5b
--- /dev/null
+++ b/app/src/main/res/drawable/notification_fastforward.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<bitmap
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/media_fastforward_dark"/> \ No newline at end of file
diff --git a/app/src/main/res/drawable/notification_rewind.xml b/app/src/main/res/drawable/notification_rewind.xml
new file mode 100644
index 00000000..ab7827a9
--- /dev/null
+++ b/app/src/main/res/drawable/notification_rewind.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<bitmap
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/media_rewind_dark"/> \ No newline at end of file
diff --git a/app/src/main/res/layout/abstract_fragment_activity.xml b/app/src/main/res/layout/abstract_fragment_activity.xml
index 180cce97..462ee7ef 100644
--- a/app/src/main/res/layout/abstract_fragment_activity.xml
+++ b/app/src/main/res/layout/abstract_fragment_activity.xml
@@ -105,6 +105,13 @@
<ImageButton
style="@style/PlaybackControl.BottomBar"
+ android:id="@+id/download_rewind"
+ android:src="?attr/actionbar_rewind"
+ android:padding="2dp"
+ android:visibility="gone"/>
+
+ <ImageButton
+ style="@style/PlaybackControl.BottomBar"
android:id="@+id/download_previous"
android:src="?attr/actionbar_backward"
android:padding="2dp"/>
@@ -119,6 +126,13 @@
android:id="@+id/download_next"
android:src="?attr/actionbar_forward"
android:padding="2dp"/>
+
+ <ImageButton
+ style="@style/PlaybackControl.BottomBar"
+ android:id="@+id/download_fastforward"
+ android:src="?attr/actionbar_fastforward"
+ android:padding="2dp"
+ android:visibility="gone"/>
</LinearLayout>
</LinearLayout>
</FrameLayout>
diff --git a/app/src/main/res/layout/download_media_buttons.xml b/app/src/main/res/layout/download_media_buttons.xml
index 58fda5c0..0610c5f9 100644
--- a/app/src/main/res/layout/download_media_buttons.xml
+++ b/app/src/main/res/layout/download_media_buttons.xml
@@ -21,6 +21,14 @@
android:layout_centerVertical="true"
/>
+ <github.daneren2005.dsub.view.AutoRepeatButton
+ style="@style/PlaybackControl.Large"
+ android:id="@+id/download_rewind"
+ android:src="?attr/media_button_rewind"
+ android:layout_toLeftOf="@+id/download_pause"
+ android:layout_centerVertical="true"
+ android:visibility="invisible"/>
+
<ImageButton
style="@style/PlaybackControl.Large"
android:id="@+id/download_pause"
@@ -44,6 +52,14 @@
android:layout_centerInParent="true"
/>
+ <github.daneren2005.dsub.view.AutoRepeatButton
+ style="@style/PlaybackControl.Large"
+ android:id="@+id/download_fastforward"
+ android:src="?attr/media_button_fastforward"
+ android:layout_toRightOf="@+id/download_start"
+ android:layout_centerVertical="true"
+ android:visibility="invisible"/>
+
<github.daneren2005.dsub.view.AutoRepeatButton
style="@style/PlaybackControl.Small"
android:id="@+id/download_next"
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index c8553dc0..2d3794d6 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -3,6 +3,8 @@
<attr name="offline_icon" format="reference"/>
<attr name="media_button_backward" format="reference"/>
<attr name="media_button_forward" format="reference"/>
+ <attr name="media_button_rewind" format="reference"/>
+ <attr name="media_button_fastforward" format="reference"/>
<attr name="media_button_pause" format="reference"/>
<attr name="media_button_repeat_off" format="reference"/>
<attr name="media_button_repeat_single" format="reference"/>
@@ -14,6 +16,8 @@
<attr name="actionbar_pause" format="reference"/>
<attr name="actionbar_start" format="reference"/>
<attr name="actionbar_stop" format="reference"/>
+ <attr name="actionbar_rewind" format="reference"/>
+ <attr name="actionbar_fastforward" format="reference"/>
<attr name="chat_send" format="reference"/>
<attr name="add" format="reference"/>
<attr name="download_none" format="reference"/>
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 4915c012..e86084b0 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -4,6 +4,8 @@
<item name="offline_icon">@drawable/main_offline_light</item>
<item name="media_button_backward">@drawable/media_backward_light</item>
<item name="media_button_forward">@drawable/media_forward_light</item>
+ <item name="media_button_rewind">@drawable/media_rewind_light</item>
+ <item name="media_button_fastforward">@drawable/media_fastforward_light</item>
<item name="media_button_pause">@drawable/media_pause_light</item>
<item name="media_button_repeat_off">@drawable/media_repeat_off_light</item>
<item name="media_button_repeat_single">@drawable/media_repeat_single_light</item>
@@ -15,6 +17,8 @@
<item name="actionbar_pause">@drawable/media_pause_dark</item>
<item name="actionbar_start">@drawable/media_start_dark</item>
<item name="actionbar_stop">@drawable/media_stop_dark</item>
+ <item name="actionbar_rewind">@drawable/media_rewind_dark</item>
+ <item name="actionbar_fastforward">@drawable/media_fastforward_dark</item>
<item name="chat_send">@drawable/ic_menu_chat_send_light</item>
<item name="add">@drawable/ic_action_add_dark</item>
<item name="download_none">@drawable/download_none_light</item>
@@ -70,6 +74,8 @@
<item name="offline_icon">@drawable/main_offline_dark</item>
<item name="media_button_backward">@drawable/media_backward_dark</item>
<item name="media_button_forward">@drawable/media_forward_dark</item>
+ <item name="media_button_rewind">@drawable/media_rewind_dark</item>
+ <item name="media_button_fastforward">@drawable/media_fastforward_dark</item>
<item name="media_button_pause">@drawable/media_pause_dark</item>
<item name="media_button_repeat_off">@drawable/media_repeat_off_dark</item>
<item name="media_button_repeat_single">@drawable/media_repeat_single_dark</item>
@@ -81,6 +87,8 @@
<item name="actionbar_pause">@drawable/media_pause_dark</item>
<item name="actionbar_start">@drawable/media_start_dark</item>
<item name="actionbar_stop">@drawable/media_stop_dark</item>
+ <item name="actionbar_rewind">@drawable/media_rewind_dark</item>
+ <item name="actionbar_fastforward">@drawable/media_fastforward_dark</item>
<item name="chat_send">@drawable/ic_menu_chat_send_dark</item>
<item name="add">@drawable/ic_action_add_dark</item>
<item name="download_none">@drawable/download_none_dark</item>
@@ -183,6 +191,8 @@
<item name="actionbar_pause">@drawable/media_pause_light</item>
<item name="actionbar_start">@drawable/media_start_light</item>
<item name="actionbar_stop">@drawable/media_stop_light</item>
+ <item name="actionbar_rewind">@drawable/media_rewind_light</item>
+ <item name="actionbar_fastforward">@drawable/media_fastforward_light</item>
<item name="add">@drawable/ic_action_add_light</item>
<item name="shuffle">@drawable/ic_menu_shuffle_light</item>
<item name="refresh">@drawable/ic_menu_refresh_light</item>