summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/build.gradle2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java11
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java173
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java214
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java2
-rw-r--r--app/src/main/res/layout/episodes_apply_action_fragment.xml2
-rw-r--r--app/src/main/res/xml/preferences.xml8
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java27
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java33
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java47
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceStateManager.java13
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/TimeSpeedConverter.java7
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/MediaPlayerError.java8
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java8
-rw-r--r--core/src/main/res/drawable/ic_fab_edit_black.xml5
-rw-r--r--core/src/main/res/drawable/ic_fab_edit_white.xml (renamed from core/src/main/res/drawable/ic_fab_edit.xml)0
-rw-r--r--core/src/main/res/drawable/ic_stream_white.xml5
-rw-r--r--core/src/main/res/values/attrs.xml1
-rw-r--r--core/src/main/res/values/strings.xml6
-rw-r--r--core/src/main/res/values/styles.xml24
21 files changed, 368 insertions, 233 deletions
diff --git a/app/build.gradle b/app/build.gradle
index a97bac1b2..e4ed38f52 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -172,7 +172,7 @@ dependencies {
implementation "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion"
implementation 'com.github.mfietz:fyydlin:v0.4.2'
- implementation 'com.github.ByteHamster:SearchPreference:v1.2.6'
+ implementation 'com.github.ByteHamster:SearchPreference:v1.3.0'
implementation "org.awaitility:awaitility:$awaitilityVersion"
androidTestImplementation 'com.nanohttpd:nanohttpd-webserver:2.1.1'
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
index 2bcd7a461..9db860598 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -76,14 +76,7 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
}
float speed = 1.0f;
if(controller.canSetPlaybackSpeed()) {
- try {
- // we can only retrieve the playback speed from the controller/playback service
- // once mediaplayer has been initialized
- speed = Float.parseFloat(UserPreferences.getPlaybackSpeed());
- } catch (NumberFormatException e) {
- Log.e(TAG, Log.getStackTraceString(e));
- UserPreferences.setPlaybackSpeed(String.valueOf(speed));
- }
+ speed = UserPreferences.getPlaybackSpeed();
}
String speedStr = new DecimalFormat("0.00x").format(speed);
butPlaybackSpeed.setText(speedStr);
@@ -105,7 +98,7 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
}
if (controller.canSetPlaybackSpeed()) {
String[] availableSpeeds = UserPreferences.getPlaybackSpeedArray();
- String currentSpeed = UserPreferences.getPlaybackSpeed();
+ String currentSpeed = new DecimalFormat("0.00x").format(UserPreferences.getPlaybackSpeed());
// Provide initial value in case the speed list has changed
// out from under us
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
index 3946400a4..52497a27f 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -22,8 +22,6 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
-import android.widget.Button;
-import android.widget.CheckBox;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
@@ -35,8 +33,6 @@ import com.bumptech.glide.Glide;
import com.joanzapata.iconify.IconDrawable;
import com.joanzapata.iconify.fonts.FontAwesomeIcons;
-import java.util.Locale;
-
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
@@ -44,7 +40,6 @@ import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.Consumer;
import de.danoeh.antennapod.core.util.Converter;
@@ -62,8 +57,8 @@ import de.danoeh.antennapod.core.util.playback.MediaPlayerError;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
+import de.danoeh.antennapod.dialog.PlaybackControlsDialog;
import de.danoeh.antennapod.dialog.SleepTimerDialog;
-import de.danoeh.antennapod.dialog.VariableSpeedDialog;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
@@ -79,9 +74,6 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
private static final String PREFS = "MediaPlayerActivityPreferences";
private static final String PREF_SHOW_TIME_LEFT = "showTimeLeft";
private static final int REQUEST_CODE_STORAGE = 42;
- private static final float PLAYBACK_SPEED_STEP = 0.05f;
- private static final float DEFAULT_MIN_PLAYBACK_SPEED = 0.5f;
- private static final float DEFAULT_MAX_PLAYBACK_SPEED = 2.5f;
PlaybackController controller;
@@ -365,7 +357,8 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
menu.findItem(R.id.audio_controls).setIcon(new IconDrawable(this,
FontAwesomeIcons.fa_sliders).color(textColor).actionBarSize());
} else {
- menu.findItem(R.id.audio_controls).setVisible(false);
+ menu.findItem(R.id.audio_controls).setIcon(new IconDrawable(this,
+ FontAwesomeIcons.fa_sliders).color(0xffffffff).actionBarSize());
}
return true;
@@ -451,148 +444,9 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
}
break;
case R.id.audio_controls:
- MaterialDialog dialog = new MaterialDialog.Builder(this)
- .title(R.string.audio_controls)
- .customView(R.layout.audio_controls, true)
- .neutralText(R.string.close_label)
- .onNeutral((dialog1, which) -> {
- final SeekBar left = (SeekBar) dialog1.findViewById(R.id.volume_left);
- final SeekBar right = (SeekBar) dialog1.findViewById(R.id.volume_right);
- UserPreferences.setVolume(left.getProgress(), right.getProgress());
- })
- .show();
- final SeekBar barPlaybackSpeed = (SeekBar) dialog.findViewById(R.id.playback_speed);
- final Button butDecSpeed = (Button) dialog.findViewById(R.id.butDecSpeed);
- butDecSpeed.setOnClickListener(v -> {
- if(controller != null && controller.canSetPlaybackSpeed()) {
- barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() - 1);
- } else {
- VariableSpeedDialog.showGetPluginDialog(this);
- }
- });
- final Button butIncSpeed = (Button) dialog.findViewById(R.id.butIncSpeed);
- butIncSpeed.setOnClickListener(v -> {
- if(controller != null && controller.canSetPlaybackSpeed()) {
- barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() + 1);
- } else {
- VariableSpeedDialog.showGetPluginDialog(this);
- }
- });
-
- final TextView txtvPlaybackSpeed = (TextView) dialog.findViewById(R.id.txtvPlaybackSpeed);
- float currentSpeed = 1.0f;
- try {
- currentSpeed = Float.parseFloat(UserPreferences.getPlaybackSpeed());
- } catch (NumberFormatException e) {
- Log.e(TAG, Log.getStackTraceString(e));
- UserPreferences.setPlaybackSpeed(String.valueOf(currentSpeed));
- }
-
- String[] availableSpeeds = UserPreferences.getPlaybackSpeedArray();
- final float minPlaybackSpeed = availableSpeeds.length > 1 ?
- Float.valueOf(availableSpeeds[0]) : DEFAULT_MIN_PLAYBACK_SPEED;
- float maxPlaybackSpeed = availableSpeeds.length > 1 ?
- Float.valueOf(availableSpeeds[availableSpeeds.length - 1]) : DEFAULT_MAX_PLAYBACK_SPEED;
- int progressMax = (int) ((maxPlaybackSpeed - minPlaybackSpeed) / PLAYBACK_SPEED_STEP);
- barPlaybackSpeed.setMax(progressMax);
-
- txtvPlaybackSpeed.setText(String.format("%.2fx", currentSpeed));
- barPlaybackSpeed.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- if(controller != null && controller.canSetPlaybackSpeed()) {
- float playbackSpeed = progress * PLAYBACK_SPEED_STEP + minPlaybackSpeed;
- controller.setPlaybackSpeed(playbackSpeed);
- String speedPref = String.format(Locale.US, "%.2f", playbackSpeed);
- UserPreferences.setPlaybackSpeed(speedPref);
- String speedStr = String.format("%.2fx", playbackSpeed);
- txtvPlaybackSpeed.setText(speedStr);
- } else if(fromUser) {
- float speed = Float.valueOf(UserPreferences.getPlaybackSpeed());
- barPlaybackSpeed.post(() -> barPlaybackSpeed.setProgress(
- (int) ((speed - minPlaybackSpeed) / PLAYBACK_SPEED_STEP)));
- }
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- if(controller != null && !controller.canSetPlaybackSpeed()) {
- VariableSpeedDialog.showGetPluginDialog(MediaplayerActivity.this);
- }
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
- });
- barPlaybackSpeed.setProgress((int) ((currentSpeed - minPlaybackSpeed) / PLAYBACK_SPEED_STEP));
-
- final SeekBar barLeftVolume = (SeekBar) dialog.findViewById(R.id.volume_left);
- barLeftVolume.setProgress(UserPreferences.getLeftVolumePercentage());
- final SeekBar barRightVolume = (SeekBar) dialog.findViewById(R.id.volume_right);
- barRightVolume.setProgress(UserPreferences.getRightVolumePercentage());
- final CheckBox stereoToMono = (CheckBox) dialog.findViewById(R.id.stereo_to_mono);
- stereoToMono.setChecked(UserPreferences.stereoToMono());
- if (controller != null && !controller.canDownmix()) {
- stereoToMono.setEnabled(false);
- String sonicOnly = getString(R.string.sonic_only);
- stereoToMono.setText(stereoToMono.getText() + " [" + sonicOnly + "]");
- }
-
- if (UserPreferences.useExoplayer()) {
- barRightVolume.setEnabled(false);
- }
-
- final CheckBox skipSilence = (CheckBox) dialog.findViewById(R.id.skipSilence);
- skipSilence.setChecked(UserPreferences.isSkipSilence());
- if (!UserPreferences.useExoplayer()) {
- skipSilence.setEnabled(false);
- String exoplayerOnly = getString(R.string.exoplayer_only);
- skipSilence.setText(skipSilence.getText() + " [" + exoplayerOnly + "]");
- }
- skipSilence.setOnCheckedChangeListener((buttonView, isChecked) -> {
- UserPreferences.setSkipSilence(isChecked);
- controller.setSkipSilence(isChecked);
- });
-
- barLeftVolume.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- controller.setVolume(
- Converter.getVolumeFromPercentage(progress),
- Converter.getVolumeFromPercentage(barRightVolume.getProgress()));
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
- });
- barRightVolume.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- controller.setVolume(
- Converter.getVolumeFromPercentage(barLeftVolume.getProgress()),
- Converter.getVolumeFromPercentage(progress));
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
- });
- stereoToMono.setOnCheckedChangeListener((buttonView, isChecked) -> {
- UserPreferences.stereoToMono(isChecked);
- if (controller != null) {
- controller.setDownmix(isChecked);
- }
- });
+ boolean isPlayingVideo = controller.getMedia().getMediaType() == MediaType.VIDEO;
+ PlaybackControlsDialog dialog = PlaybackControlsDialog.newInstance(isPlayingVideo);
+ dialog.show(getSupportFragmentManager(), "playback_controls");
break;
case R.id.visit_website_item:
Uri uri = Uri.parse(getWebsiteLinkWithFallback(media));
@@ -666,9 +520,10 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
return;
}
- int currentPosition = TimeSpeedConverter.convert(controller.getPosition());
- int duration = TimeSpeedConverter.convert(controller.getDuration());
- int remainingTime = TimeSpeedConverter.convert(
+ TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier());
+ int currentPosition = converter.convert(controller.getPosition());
+ int duration = converter.convert(controller.getDuration());
+ int remainingTime = converter.convert(
controller.getDuration() - controller.getPosition());
Log.d(TAG, "currentPosition " + Converter.getDurationStringLong(currentPosition));
if (currentPosition == PlaybackService.INVALID_TIME ||
@@ -824,14 +679,15 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
return;
}
+ TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier());
String length;
if (showTimeLeft) {
- int remainingTime = TimeSpeedConverter.convert(
+ int remainingTime = converter.convert(
media.getDuration() - media.getPosition());
length = "-" + Converter.getDurationStringLong(remainingTime);
} else {
- int duration = TimeSpeedConverter.convert(media.getDuration());
+ int duration = converter.convert(media.getDuration());
length = Converter.getDurationStringLong(duration);
}
txtvLength.setText(length);
@@ -935,7 +791,8 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
prog = controller.onSeekBarProgressChanged(seekBar, progress, fromUser, txtvPosition);
if (showTimeLeft && prog != 0) {
int duration = controller.getDuration();
- int timeLeft = TimeSpeedConverter.convert(duration - (int) (prog * duration));
+ TimeSpeedConverter converter = new TimeSpeedConverter(controller.getCurrentPlaybackSpeedMultiplier());
+ int timeLeft = converter.convert(duration - (int) (prog * duration));
String length = "-" + Converter.getDurationStringLong(timeLeft);
txtvLength.setText(length);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
new file mode 100644
index 000000000..e8c7520b7
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
@@ -0,0 +1,214 @@
+package de.danoeh.antennapod.dialog;
+
+import android.app.Dialog;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.DialogFragment;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.SeekBar;
+import android.widget.TextView;
+import com.afollestad.materialdialogs.MaterialDialog;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.util.Converter;
+import de.danoeh.antennapod.core.util.playback.PlaybackController;
+
+import java.util.Locale;
+
+public class PlaybackControlsDialog extends DialogFragment {
+ private static final float PLAYBACK_SPEED_STEP = 0.05f;
+ private static final float DEFAULT_MIN_PLAYBACK_SPEED = 0.5f;
+ private static final float DEFAULT_MAX_PLAYBACK_SPEED = 2.5f;
+ private static final String ARGUMENT_IS_PLAYING_VIDEO = "isPlayingVideo";
+
+ private PlaybackController controller;
+ private MaterialDialog dialog;
+ private boolean isPlayingVideo;
+
+ public static PlaybackControlsDialog newInstance(boolean isPlayingVideo) {
+ Bundle arguments = new Bundle();
+ arguments.putBoolean(ARGUMENT_IS_PLAYING_VIDEO, isPlayingVideo);
+ PlaybackControlsDialog dialog = new PlaybackControlsDialog();
+ dialog.setArguments(arguments);
+ return dialog;
+ }
+
+ public PlaybackControlsDialog() {
+ // Empty constructor required for DialogFragment
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ controller = new PlaybackController(getActivity(), false);
+ controller.init();
+ setupUi();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ controller.release();
+ controller = null;
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ isPlayingVideo = getArguments() != null && getArguments().getBoolean(ARGUMENT_IS_PLAYING_VIDEO);
+
+ dialog = new MaterialDialog.Builder(getContext())
+ .title(R.string.audio_controls)
+ .customView(R.layout.audio_controls, true)
+ .neutralText(R.string.close_label)
+ .onNeutral((dialog1, which) -> {
+ final SeekBar left = (SeekBar) dialog1.findViewById(R.id.volume_left);
+ final SeekBar right = (SeekBar) dialog1.findViewById(R.id.volume_right);
+ UserPreferences.setVolume(left.getProgress(), right.getProgress());
+ }).build();
+ return dialog;
+ }
+
+ private void setupUi() {
+ final SeekBar barPlaybackSpeed = (SeekBar) dialog.findViewById(R.id.playback_speed);
+ final Button butDecSpeed = (Button) dialog.findViewById(R.id.butDecSpeed);
+ butDecSpeed.setOnClickListener(v -> {
+ if (controller != null && controller.canSetPlaybackSpeed()) {
+ barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() - 1);
+ } else {
+ VariableSpeedDialog.showGetPluginDialog(getContext());
+ }
+ });
+ final Button butIncSpeed = (Button) dialog.findViewById(R.id.butIncSpeed);
+ butIncSpeed.setOnClickListener(v -> {
+ if (controller != null && controller.canSetPlaybackSpeed()) {
+ barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() + 1);
+ } else {
+ VariableSpeedDialog.showGetPluginDialog(getContext());
+ }
+ });
+
+ final TextView txtvPlaybackSpeed = (TextView) dialog.findViewById(R.id.txtvPlaybackSpeed);
+ float currentSpeed = getCurrentSpeed();
+
+ String[] availableSpeeds = UserPreferences.getPlaybackSpeedArray();
+ final float minPlaybackSpeed = availableSpeeds.length > 1 ?
+ Float.valueOf(availableSpeeds[0]) : DEFAULT_MIN_PLAYBACK_SPEED;
+ float maxPlaybackSpeed = availableSpeeds.length > 1 ?
+ Float.valueOf(availableSpeeds[availableSpeeds.length - 1]) : DEFAULT_MAX_PLAYBACK_SPEED;
+ int progressMax = (int) ((maxPlaybackSpeed - minPlaybackSpeed) / PLAYBACK_SPEED_STEP);
+ barPlaybackSpeed.setMax(progressMax);
+
+ txtvPlaybackSpeed.setText(String.format("%.2fx", currentSpeed));
+ barPlaybackSpeed.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if (controller != null && controller.canSetPlaybackSpeed()) {
+ float playbackSpeed = progress * PLAYBACK_SPEED_STEP + minPlaybackSpeed;
+ controller.setPlaybackSpeed(playbackSpeed);
+ String speedPref = String.format(Locale.US, "%.2f", playbackSpeed);
+
+ if (isPlayingVideo) {
+ UserPreferences.setVideoPlaybackSpeed(speedPref);
+ } else {
+ UserPreferences.setPlaybackSpeed(speedPref);
+ }
+
+ String speedStr = String.format("%.2fx", playbackSpeed);
+ txtvPlaybackSpeed.setText(speedStr);
+ } else if (fromUser) {
+ float speed = getCurrentSpeed();
+ barPlaybackSpeed.post(() -> barPlaybackSpeed.setProgress(
+ (int) ((speed - minPlaybackSpeed) / PLAYBACK_SPEED_STEP)));
+ }
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ if (controller != null && !controller.canSetPlaybackSpeed()) {
+ VariableSpeedDialog.showGetPluginDialog(getContext());
+ }
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+ barPlaybackSpeed.setProgress((int) ((currentSpeed - minPlaybackSpeed) / PLAYBACK_SPEED_STEP));
+
+ final SeekBar barLeftVolume = (SeekBar) dialog.findViewById(R.id.volume_left);
+ barLeftVolume.setProgress(UserPreferences.getLeftVolumePercentage());
+ final SeekBar barRightVolume = (SeekBar) dialog.findViewById(R.id.volume_right);
+ barRightVolume.setProgress(UserPreferences.getRightVolumePercentage());
+ final CheckBox stereoToMono = (CheckBox) dialog.findViewById(R.id.stereo_to_mono);
+ stereoToMono.setChecked(UserPreferences.stereoToMono());
+ if (controller != null && !controller.canDownmix()) {
+ stereoToMono.setEnabled(false);
+ String sonicOnly = getString(R.string.sonic_only);
+ stereoToMono.setText(stereoToMono.getText() + " [" + sonicOnly + "]");
+ }
+
+ if (UserPreferences.useExoplayer()) {
+ barRightVolume.setEnabled(false);
+ }
+
+ final CheckBox skipSilence = (CheckBox) dialog.findViewById(R.id.skipSilence);
+ skipSilence.setChecked(UserPreferences.isSkipSilence());
+ if (!UserPreferences.useExoplayer()) {
+ skipSilence.setEnabled(false);
+ String exoplayerOnly = getString(R.string.exoplayer_only);
+ skipSilence.setText(skipSilence.getText() + " [" + exoplayerOnly + "]");
+ }
+ skipSilence.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ UserPreferences.setSkipSilence(isChecked);
+ controller.setSkipSilence(isChecked);
+ });
+
+ barLeftVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ controller.setVolume(
+ Converter.getVolumeFromPercentage(progress),
+ Converter.getVolumeFromPercentage(barRightVolume.getProgress()));
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+ barRightVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ controller.setVolume(
+ Converter.getVolumeFromPercentage(barLeftVolume.getProgress()),
+ Converter.getVolumeFromPercentage(progress));
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+ stereoToMono.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ UserPreferences.stereoToMono(isChecked);
+ if (controller != null) {
+ controller.setDownmix(isChecked);
+ }
+ });
+ }
+
+ private float getCurrentSpeed() {
+ if (isPlayingVideo) {
+ return UserPreferences.getVideoPlaybackSpeed();
+ }
+ return UserPreferences.getPlaybackSpeed();
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
index e22a70584..4f07e1b59 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -596,7 +596,7 @@ public class QueueFragment extends Fragment {
String info = queue.size() + getString(R.string.episodes_suffix);
if(queue.size() > 0) {
long timeLeft = 0;
- float playbackSpeed = Float.valueOf(UserPreferences.getPlaybackSpeed());
+ float playbackSpeed = UserPreferences.getPlaybackSpeed();
for(FeedItem item : queue) {
if(item.getMedia() != null) {
timeLeft +=
diff --git a/app/src/main/res/layout/episodes_apply_action_fragment.xml b/app/src/main/res/layout/episodes_apply_action_fragment.xml
index 984e960d8..d6e18bb37 100644
--- a/app/src/main/res/layout/episodes_apply_action_fragment.xml
+++ b/app/src/main/res/layout/episodes_apply_action_fragment.xml
@@ -39,7 +39,7 @@
android:id="@+id/fabSD"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- app:sdMainFabClosedSrc="@drawable/ic_fab_edit"
+ app:sdMainFabClosedSrc="?attr/batch_edit_fab_icon"
app:sdOverlayLayout="@id/fabSDOverlay"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index f45847e54..6c1e470c0 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -1,9 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
- xmlns:android="http://schemas.android.com/apk/res/android">
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:search="http://schemas.android.com/apk/res-auto">
<com.bytehamster.lib.preferencesearch.SearchPreference
- android:key="searchPreference" />
+ android:key="searchPreference"
+ search:textHint="@string/preference_search_hint"
+ search:textNoResults="@string/preference_search_no_results"
+ search:textClearHistory="@string/preference_search_clear_history" />
<Preference
android:key="prefScreenInterface"
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
index 4cc1a9c32..b8ab1c888 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
@@ -109,6 +109,7 @@ public class UserPreferences {
public static final String PREF_MEDIA_PLAYER = "prefMediaPlayer";
public static final String PREF_MEDIA_PLAYER_EXOPLAYER = "exoplayer";
private static final String PREF_PLAYBACK_SPEED = "prefPlaybackSpeed";
+ private static final String PREF_VIDEO_PLAYBACK_SPEED = "prefVideoPlaybackSpeed";
public static final String PREF_PLAYBACK_SKIP_SILENCE = "prefSkipSilence";
private static final String PREF_FAST_FORWARD_SECS = "prefFastForwardSecs";
private static final String PREF_REWIND_SECS = "prefRewindSecs";
@@ -319,8 +320,24 @@ public class UserPreferences {
return prefs.getBoolean(PREF_DELETE_REMOVES_FROM_QUEUE, false);
}
- public static String getPlaybackSpeed() {
- return prefs.getString(PREF_PLAYBACK_SPEED, "1.00");
+ public static float getPlaybackSpeed() {
+ try {
+ return Float.parseFloat(prefs.getString(PREF_PLAYBACK_SPEED, "1.00"));
+ } catch (NumberFormatException e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ UserPreferences.setPlaybackSpeed("1.00");
+ return 1.0f;
+ }
+ }
+
+ public static float getVideoPlaybackSpeed() {
+ try {
+ return Float.parseFloat(prefs.getString(PREF_VIDEO_PLAYBACK_SPEED, "1.00"));
+ } catch (NumberFormatException e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ UserPreferences.setVideoPlaybackSpeed("1.00");
+ return 1.0f;
+ }
}
public static boolean isSkipSilence() {
@@ -559,6 +576,12 @@ public class UserPreferences {
.apply();
}
+ public static void setVideoPlaybackSpeed(String speed) {
+ prefs.edit()
+ .putString(PREF_VIDEO_PLAYBACK_SPEED, speed)
+ .apply();
+ }
+
public static void setSkipSilence(boolean skipSilence) {
prefs.edit()
.putBoolean(PREF_PLAYBACK_SKIP_SILENCE, skipSilence)
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java b/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java
index b26d3011d..7938e262d 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java
@@ -213,8 +213,9 @@ public class PlayerWidgetJobService extends SafeJobIntentService {
private String getProgressString(int position, int duration) {
if (position > 0 && duration > 0) {
- position = TimeSpeedConverter.convert(position);
- duration = TimeSpeedConverter.convert(duration);
+ TimeSpeedConverter converter = new TimeSpeedConverter(playbackService.getCurrentPlaybackSpeed());
+ position = converter.convert(position);
+ duration = converter.convert(duration);
return Converter.getDurationStringLong(position) + " / "
+ Converter.getDurationStringLong(duration);
} else {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
index 9a8353806..6bd736de7 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
@@ -303,14 +303,11 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
Log.d(TAG, "Audiofocus successfully requested");
Log.d(TAG, "Resuming/Starting playback");
acquireWifiLockIfNecessary();
- float speed = 1.0f;
- try {
- speed = Float.parseFloat(UserPreferences.getPlaybackSpeed());
- } catch(NumberFormatException e) {
- Log.e(TAG, Log.getStackTraceString(e));
- UserPreferences.setPlaybackSpeed(String.valueOf(speed));
+ if (media.getMediaType() == MediaType.VIDEO) {
+ setPlaybackParams(UserPreferences.getVideoPlaybackSpeed(), UserPreferences.isSkipSilence());
+ } else {
+ setPlaybackParams(UserPreferences.getPlaybackSpeed(), UserPreferences.isSkipSilence());
}
- setPlaybackParams(speed, UserPreferences.isSkipSilence());
setVolume(UserPreferences.getLeftVolume(), UserPreferences.getRightVolume());
if (playerStatus == PlayerStatus.PREPARED && media.getPosition() > 0) {
@@ -601,11 +598,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
*/
@Override
public boolean canSetSpeed() {
- boolean retVal = false;
- if (mediaPlayer != null && media != null && media.getMediaType() == MediaType.AUDIO) {
- retVal = (mediaPlayer).canSetSpeed();
- }
- return retVal;
+ return mediaPlayer != null && mediaPlayer.canSetSpeed();
}
/**
@@ -614,13 +607,11 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
*/
private void setSpeedSyncAndSkipSilence(float speed, boolean skipSilence) {
playerLock.lock();
- if (media != null && media.getMediaType() == MediaType.AUDIO) {
- if (mediaPlayer.canSetSpeed()) {
- Log.d(TAG, "Playback speed was set to " + speed);
- callback.playbackSpeedChanged(speed);
- }
- mediaPlayer.setPlaybackParams(speed, skipSilence);
+ if (mediaPlayer.canSetSpeed()) {
+ Log.d(TAG, "Playback speed was set to " + speed);
+ callback.playbackSpeedChanged(speed);
}
+ mediaPlayer.setPlaybackParams(speed, skipSilence);
playerLock.unlock();
}
@@ -667,10 +658,8 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
*/
private void setVolumeSync(float volumeLeft, float volumeRight) {
playerLock.lock();
- if (media != null && media.getMediaType() == MediaType.AUDIO) {
- mediaPlayer.setVolume(volumeLeft, volumeRight);
- Log.d(TAG, "Media player volume was set to " + volumeLeft + " " + volumeRight);
- }
+ mediaPlayer.setVolume(volumeLeft, volumeRight);
+ Log.d(TAG, "Media player volume was set to " + volumeLeft + " " + volumeRight);
playerLock.unlock();
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
index 8089bcbb6..f7a13d81e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
@@ -98,6 +98,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
*/
public static final String EXTRA_SHOULD_STREAM = "extra.de.danoeh.antennapod.core.service.shouldStream";
public static final String EXTRA_ALLOW_STREAM_THIS_TIME = "extra.de.danoeh.antennapod.core.service.allowStream";
+ public static final String EXTRA_ALLOW_STREAM_ALWAYS = "extra.de.danoeh.antennapod.core.service.allowStreamAlways";
/**
* True if playback should be started immediately after media has been
* prepared.
@@ -326,7 +327,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "Service is about to be destroyed");
- stateManager.stopForeground(true);
+ stateManager.stopForeground(!UserPreferences.isPersistNotify());
isRunning = false;
currentMediaType = MediaType.UNKNOWN;
@@ -444,9 +445,18 @@ public class PlaybackService extends MediaBrowserServiceCompat {
if (!stateManager.isInForeground()) {
PlaybackServiceNotificationBuilder notificationBuilder = new PlaybackServiceNotificationBuilder(this);
+ if (mediaPlayer != null && getPlayable() != null) {
+ notificationBuilder.addMetadata(getPlayable(), mediaSession.getSessionToken(), getStatus(), isCasting);
+ if (notificationBuilder.isIconCached(getPlayable())) {
+ notificationBuilder.loadIcon(getPlayable());
+ }
+ }
startForeground(NOTIFICATION_ID, notificationBuilder.build());
}
+ NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
+ notificationManager.cancel(NOTIFICATION_ID_STREAMING);
+
final int keycode = intent.getIntExtra(MediaButtonReceiver.EXTRA_KEYCODE, -1);
final boolean castDisconnect = intent.getBooleanExtra(EXTRA_CAST_DISCONNECT, false);
Playable playable = intent.getParcelableExtra(EXTRA_PLAYABLE);
@@ -471,6 +481,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
stateManager.validStartCommandWasReceived();
boolean stream = intent.getBooleanExtra(EXTRA_SHOULD_STREAM, true);
boolean allowStreamThisTime = intent.getBooleanExtra(EXTRA_ALLOW_STREAM_THIS_TIME, false);
+ boolean allowStreamAlways = intent.getBooleanExtra(EXTRA_ALLOW_STREAM_ALWAYS, false);
boolean startWhenPrepared = intent.getBooleanExtra(EXTRA_START_WHEN_PREPARED, false);
boolean prepareImmediately = intent.getBooleanExtra(EXTRA_PREPARE_IMMEDIATELY, false);
sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, 0);
@@ -479,6 +490,9 @@ public class PlaybackService extends MediaBrowserServiceCompat {
if (playable instanceof FeedMedia) {
playable = DBReader.getFeedMedia(((FeedMedia) playable).getId());
}
+ if (allowStreamAlways) {
+ UserPreferences.setAllowMobileStreaming(true);
+ }
if (stream && !NetworkUtils.isStreamingAllowed() && !allowStreamThisTime) {
displayStreamingNotAllowedNotification(intent);
writePlaybackPreferencesNoMediaPlaying();
@@ -496,23 +510,38 @@ public class PlaybackService extends MediaBrowserServiceCompat {
}
private void displayStreamingNotAllowedNotification(Intent originalIntent) {
- Intent intent = new Intent(originalIntent);
- intent.putExtra(EXTRA_ALLOW_STREAM_THIS_TIME, true);
- PendingIntent pendingIntent;
+ Intent intentAllowThisTime = new Intent(originalIntent);
+ intentAllowThisTime.putExtra(EXTRA_ALLOW_STREAM_THIS_TIME, true);
+ PendingIntent pendingIntentAllowThisTime;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
- pendingIntent = PendingIntent.getForegroundService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ pendingIntentAllowThisTime = PendingIntent.getForegroundService(this, 0, intentAllowThisTime, PendingIntent.FLAG_UPDATE_CURRENT);
} else {
- pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ pendingIntentAllowThisTime = PendingIntent.getService(this, 0, intentAllowThisTime, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
+ Intent intentAlwaysAllow = new Intent(intentAllowThisTime);
+ intentAlwaysAllow.putExtra(EXTRA_ALLOW_STREAM_ALWAYS, true);
+ PendingIntent pendingIntentAlwaysAllow;
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
+ pendingIntentAlwaysAllow = PendingIntent.getForegroundService(this, 0, intentAlwaysAllow, PendingIntent.FLAG_UPDATE_CURRENT);
+ } else {
+ pendingIntentAlwaysAllow = PendingIntent.getService(this, 0, intentAlwaysAllow, PendingIntent.FLAG_UPDATE_CURRENT);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NotificationUtils.CHANNEL_ID_USER_ACTION)
- .setSmallIcon(R.drawable.stat_notify_sync_error)
+ .setSmallIcon(R.drawable.ic_stream_white)
.setContentTitle(getString(R.string.confirm_mobile_streaming_notification_title))
.setContentText(getString(R.string.confirm_mobile_streaming_notification_message))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(getString(R.string.confirm_mobile_streaming_notification_message)))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
- .setContentIntent(pendingIntent)
+ .setContentIntent(pendingIntentAllowThisTime)
+ .addAction(R.drawable.ic_stream_white,
+ getString(R.string.stream_label),
+ pendingIntentAllowThisTime)
+ .addAction(R.drawable.ic_stream_white,
+ getString(R.string.confirm_mobile_streaming_button_always),
+ pendingIntentAlwaysAllow)
.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(NOTIFICATION_ID_STREAMING, builder.build());
@@ -733,7 +762,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
@Override
public void shouldStop() {
- stateManager.stopService();
+ setupNotification(getPlayable()); // Stops foreground if not playing
}
@Override
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceStateManager.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceStateManager.java
index b8541748e..18c8fa51f 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceStateManager.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceStateManager.java
@@ -1,6 +1,8 @@
package de.danoeh.antennapod.core.service.playback;
import android.app.Notification;
+import android.app.Service;
+import android.os.Build;
class PlaybackServiceStateManager {
private final PlaybackService playbackService;
@@ -19,12 +21,19 @@ class PlaybackServiceStateManager {
void stopService() {
stopForeground(true);
- isInForeground = false;
playbackService.stopSelf();
}
void stopForeground(boolean removeNotification) {
- playbackService.stopForeground(removeNotification);
+ if (isInForeground) {
+ if (Build.VERSION.SDK_INT < 24) {
+ playbackService.stopForeground(removeNotification);
+ } else if (removeNotification) {
+ playbackService.stopForeground(Service.STOP_FOREGROUND_REMOVE);
+ } else {
+ playbackService.stopForeground(Service.STOP_FOREGROUND_DETACH);
+ }
+ }
isInForeground = false;
hasReceivedValidStartCommand = false;
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/TimeSpeedConverter.java b/core/src/main/java/de/danoeh/antennapod/core/util/TimeSpeedConverter.java
index 5fea8238b..5d44c14b8 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/TimeSpeedConverter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/TimeSpeedConverter.java
@@ -3,18 +3,19 @@ package de.danoeh.antennapod.core.util;
import de.danoeh.antennapod.core.preferences.UserPreferences;
public class TimeSpeedConverter {
- private TimeSpeedConverter() {
+ private final float speed;
+ public TimeSpeedConverter(float speed) {
+ this.speed = speed;
}
/** Convert millisecond according to the current playback speed
* @param time: time to convert
* @return converted time (can be < 0 if time is < 0)
*/
- public static int convert(int time) {
+ public int convert(int time) {
boolean timeRespectsSpeed = UserPreferences.timeRespectsSpeed();
if (time > 0 && timeRespectsSpeed) {
- float speed = Float.parseFloat(UserPreferences.getPlaybackSpeed());
return (int)(time / speed);
}
return time;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/MediaPlayerError.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/MediaPlayerError.java
index b04c02075..32d37a67e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/MediaPlayerError.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/MediaPlayerError.java
@@ -16,10 +16,16 @@ public class MediaPlayerError {
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
resId = R.string.playback_error_server_died;
break;
+ case MediaPlayer.MEDIA_ERROR_UNSUPPORTED:
+ resId = R.string.playback_error_unsupported;
+ break;
+ case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
+ resId = R.string.playback_error_timeout;
+ break;
default:
resId = R.string.playback_error_unknown;
break;
}
- return context.getString(resId);
+ return context.getString(resId) + " (" + code + ")";
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
index 5b2d7b13e..0cfaaab3c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
@@ -54,7 +54,7 @@ import org.greenrobot.eventbus.ThreadMode;
* Communicates with the playback service. GUI classes should use this class to
* control playback instead of communicating with the PlaybackService directly.
*/
-public abstract class PlaybackController {
+public class PlaybackController {
private static final String TAG = "PlaybackController";
@@ -567,7 +567,8 @@ public abstract class PlaybackController {
if (fromUser && playbackService != null && media != null) {
float prog = progress / ((float) seekBar.getMax());
int duration = media.getDuration();
- int position = TimeSpeedConverter.convert((int) (prog * duration));
+ TimeSpeedConverter converter = new TimeSpeedConverter(playbackService.getCurrentPlaybackSpeed());
+ int position = converter.convert((int) (prog * duration));
txtvPosition.setText(Converter.getDurationStringLong(position));
return prog;
}
@@ -719,6 +720,7 @@ public abstract class PlaybackController {
public boolean canSetPlaybackSpeed() {
return org.antennapod.audio.MediaPlayer.isPrestoLibraryInstalled(activity.getApplicationContext())
|| UserPreferences.useSonic()
+ || UserPreferences.useExoplayer()
|| Build.VERSION.SDK_INT >= 23
|| (playbackService != null && playbackService.canSetSpeed());
}
@@ -741,7 +743,7 @@ public abstract class PlaybackController {
}
public float getCurrentPlaybackSpeedMultiplier() {
- if (canSetPlaybackSpeed()) {
+ if (playbackService != null && canSetPlaybackSpeed()) {
return playbackService.getCurrentPlaybackSpeed();
} else {
return -1;
diff --git a/core/src/main/res/drawable/ic_fab_edit_black.xml b/core/src/main/res/drawable/ic_fab_edit_black.xml
new file mode 100644
index 000000000..a9fec7080
--- /dev/null
+++ b/core/src/main/res/drawable/ic_fab_edit_black.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp"
+ android:viewportHeight="24.0" android:viewportWidth="24.0"
+ android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#FF000000" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
+</vector>
diff --git a/core/src/main/res/drawable/ic_fab_edit.xml b/core/src/main/res/drawable/ic_fab_edit_white.xml
index cb2e394b0..cb2e394b0 100644
--- a/core/src/main/res/drawable/ic_fab_edit.xml
+++ b/core/src/main/res/drawable/ic_fab_edit_white.xml
diff --git a/core/src/main/res/drawable/ic_stream_white.xml b/core/src/main/res/drawable/ic_stream_white.xml
new file mode 100644
index 000000000..3c59bbad7
--- /dev/null
+++ b/core/src/main/res/drawable/ic_stream_white.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp"
+ android:viewportHeight="24.0" android:viewportWidth="24.0"
+ android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#FFFFFFFF" android:pathData="M12,5c-3.87,0 -7,3.13 -7,7h2c0,-2.76 2.24,-5 5,-5s5,2.24 5,5h2c0,-3.87 -3.13,-7 -7,-7zM13,14.29c0.88,-0.39 1.5,-1.26 1.5,-2.29 0,-1.38 -1.12,-2.5 -2.5,-2.5S9.5,10.62 9.5,12c0,1.02 0.62,1.9 1.5,2.29v3.3L7.59,21 9,22.41l3,-3 3,3L16.41,21 13,17.59v-3.3zM12,1C5.93,1 1,5.93 1,12h2c0,-4.97 4.03,-9 9,-9s9,4.03 9,9h2c0,-6.07 -4.93,-11 -11,-11z"/>
+</vector>
diff --git a/core/src/main/res/values/attrs.xml b/core/src/main/res/values/attrs.xml
index eb7f065ce..5b0bf5717 100644
--- a/core/src/main/res/values/attrs.xml
+++ b/core/src/main/res/values/attrs.xml
@@ -74,4 +74,5 @@
<attr name="about_screen_card_background" format="color"/>
<attr name="about_screen_card_border" format="color"/>
<attr name="about_screen_font_color" format="color"/>
+ <attr name="batch_edit_fab_icon" format="reference"/>
</resources>
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index a4084b76b..c9c6506a9 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -267,6 +267,7 @@
<string name="confirm_mobile_download_dialog_message">Downloading over mobile data connection is disabled in the settings.\n\nDo you want to allow downloading temporarily?\n\n<small>Your choice will be remembered for 10 minutes.</small></string>
<string name="confirm_mobile_streaming_notification_title">Confirm Mobile streaming</string>
<string name="confirm_mobile_streaming_notification_message">Streaming over mobile data connection is disabled in the settings. Tap to stream anyway.</string>
+ <string name="confirm_mobile_streaming_button_always">Always allow</string>
<string name="confirm_mobile_download_dialog_only_add_to_queue">Enqueue</string>
<string name="confirm_mobile_download_dialog_enable_temporarily">Allow temporarily</string>
@@ -277,6 +278,8 @@
<string name="player_ready_msg">Ready</string>
<string name="player_seeking_msg">Seeking</string>
<string name="playback_error_server_died">Server died</string>
+ <string name="playback_error_unsupported">Unsupported media type</string>
+ <string name="playback_error_timeout">Operation timed out</string>
<string name="playback_error_unknown">Unknown Error</string>
<string name="no_media_playing_label">No media playing</string>
<string name="position_default_label" translate="false">00:00:00</string>
@@ -353,6 +356,9 @@
<string name="external_elements">External elements</string>
<string name="interruptions">Interruptions</string>
<string name="playback_control">Playback control</string>
+ <string name="preference_search_hint">Search…</string>
+ <string name="preference_search_no_results">No results</string>
+ <string name="preference_search_clear_history">Clear history</string>
<string name="media_player">Media player</string>
<string name="pref_episode_cleanup_title">Episode Cleanup</string>
<string name="pref_episode_cleanup_summary">Episodes that aren\'t in the queue and aren\'t favorites should be eligible for removal if Auto Download needs space for new episodes</string>
diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml
index 4c69306a9..fb69e54e7 100644
--- a/core/src/main/res/values/styles.xml
+++ b/core/src/main/res/values/styles.xml
@@ -72,6 +72,7 @@
<item name="ic_bug">@drawable/ic_bug_grey600_24dp</item>
<item name="ic_known_issues">@drawable/ic_format_list_bulleted_grey600_24dp</item>
<item name="ic_bookmark">@drawable/ic_bookmark_grey600_24dp</item>
+ <item name="batch_edit_fab_icon">@drawable/ic_fab_edit_white</item>
<item name="master_switch_background">@color/master_switch_background_light</item>
<item name="currently_playing_background">@color/highlight_light</item>
@@ -156,6 +157,7 @@
<item name="ic_bug">@drawable/ic_bug_white_24dp</item>
<item name="ic_known_issues">@drawable/ic_format_list_bulleted_white_24dp</item>
<item name="ic_bookmark">@drawable/ic_bookmark_white_24dp</item>
+ <item name="batch_edit_fab_icon">@drawable/ic_fab_edit_white</item>
<item name="master_switch_background">@color/master_switch_background_dark</item>
<item name="currently_playing_background">@color/highlight_dark</item>
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
@@ -176,6 +178,7 @@
<item name="overlay_background">@color/black</item>
<item name="overlay_drawable">@drawable/overlay_drawable_dark_trueblack</item>
<item name="dragview_background">@drawable/ic_drag_vertical_white_48dp</item>
+ <item name="batch_edit_fab_icon">@drawable/ic_fab_edit_black</item>
<item name="dragview_float_background">@color/black</item>
<item name="nav_drawer_background">@color/black</item>
<item name="drawer_activated_color">@color/highlight_trueblack</item>
@@ -213,23 +216,10 @@
<!-- Room for API dependent attributes -->
</style>
- <style name="Theme.Base.AntennaPod.TrueBlack.NoTitle" parent="Theme.Base.AntennaPod.Dark.NoTitle">
- <item name="progressBarTheme">@style/ProgressBarTrueBlack</item>
- <item name="non_transparent_background">@color/black</item>
- <item name="overlay_background">@color/black</item>
- <item name="overlay_drawable">@drawable/overlay_drawable_dark_trueblack</item>
- <item name="dragview_background">@drawable/ic_drag_vertical_white_48dp</item>
- <item name="dragview_float_background">@color/black</item>
- <item name="nav_drawer_background">@color/black</item>
- <item name="drawer_activated_color">@color/highlight_trueblack</item>
- <item name="currently_playing_background">@color/highlight_trueblack</item>
- <item name="android:textColorPrimary">@color/white</item>
- <item name="android:color">@color/white</item>
- <item name="android:colorBackground">@color/black</item>
- <item name="android:windowBackground">@color/black</item>
- <item name="android:actionBarStyle">@color/black</item>
- <item name="colorPrimary">@color/black</item>
- <item name="colorPrimaryDark">@color/black</item>
+ <style name="Theme.Base.AntennaPod.TrueBlack.NoTitle" parent="Theme.Base.AntennaPod.TrueBlack">
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
+ <item name="windowActionModeOverlay">true</item>
</style>