diff --git a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayerActivity.java b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayerActivity.java index 8a5809b95..cc632a473 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayerActivity.java +++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayerActivity.java @@ -74,6 +74,11 @@ public class BackgroundPlayerActivity extends AppCompatActivity private ImageButton forwardButton; private ImageButton shuffleButton; + private TextView playbackSpeedButton; + private PopupMenu playbackSpeedPopupMenu; + private TextView playbackPitchButton; + private PopupMenu playbackPitchPopupMenu; + //////////////////////////////////////////////////////////////////////////// // Activity Lifecycle //////////////////////////////////////////////////////////////////////////// @@ -198,12 +203,57 @@ public class BackgroundPlayerActivity extends AppCompatActivity playPauseButton = rootView.findViewById(R.id.control_play_pause); forwardButton = rootView.findViewById(R.id.control_forward); shuffleButton = rootView.findViewById(R.id.control_shuffle); + playbackSpeedButton = rootView.findViewById(R.id.control_playback_speed); + playbackPitchButton = rootView.findViewById(R.id.control_playback_pitch); repeatButton.setOnClickListener(this); backwardButton.setOnClickListener(this); playPauseButton.setOnClickListener(this); forwardButton.setOnClickListener(this); shuffleButton.setOnClickListener(this); + playbackSpeedButton.setOnClickListener(this); + playbackPitchButton.setOnClickListener(this); + + playbackSpeedPopupMenu = new PopupMenu(this, playbackSpeedButton); + playbackPitchPopupMenu = new PopupMenu(this, playbackPitchButton); + buildPlaybackSpeedMenu(); + buildPlaybackPitchMenu(); + } + + private void buildPlaybackSpeedMenu() { + if (playbackSpeedPopupMenu == null) return; + + playbackSpeedPopupMenu.getMenu().removeGroup(PLAYBACK_SPEED_POPUP_MENU_GROUP_ID); + for (int i = 0; i < BasePlayer.PLAYBACK_SPEEDS.length; i++) { + final float playbackSpeed = BasePlayer.PLAYBACK_SPEEDS[i]; + final String formattedSpeed = player.formatSpeed(playbackSpeed); + final MenuItem item = playbackSpeedPopupMenu.getMenu().add(PLAYBACK_SPEED_POPUP_MENU_GROUP_ID, i, Menu.NONE, formattedSpeed); + item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem menuItem) { + player.setPlaybackSpeed(playbackSpeed); + return true; + } + }); + } + } + + private void buildPlaybackPitchMenu() { + if (playbackPitchPopupMenu == null) return; + + playbackPitchPopupMenu.getMenu().removeGroup(PLAYBACK_SPEED_POPUP_MENU_GROUP_ID); + for (int i = 0; i < BasePlayer.PLAYBACK_PITCHES.length; i++) { + final float playbackPitch = BasePlayer.PLAYBACK_PITCHES[i]; + final String formattedPitch = player.formatPitch(playbackPitch); + final MenuItem item = playbackPitchPopupMenu.getMenu().add(PLAYBACK_SPEED_POPUP_MENU_GROUP_ID, i, Menu.NONE, formattedPitch); + item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem menuItem) { + player.setPlaybackPitch(playbackPitch); + return true; + } + }); + } } private void buildItemPopupMenu(final PlayQueueItem item, final View view) { @@ -313,16 +363,26 @@ public class BackgroundPlayerActivity extends AppCompatActivity public void onClick(View view) { if (view.getId() == repeatButton.getId()) { player.onRepeatClicked(); + } else if (view.getId() == backwardButton.getId()) { player.onPlayPrevious(); scrollToSelected(); + } else if (view.getId() == playPauseButton.getId()) { player.onVideoPlayPause(); scrollToSelected(); + } else if (view.getId() == forwardButton.getId()) { player.onPlayNext(); + } else if (view.getId() == shuffleButton.getId()) { player.onShuffleClicked(); + + } else if (view.getId() == playbackSpeedButton.getId()) { + playbackSpeedPopupMenu.show(); + + } else if (view.getId() == playbackPitchButton.getId()) { + playbackPitchPopupMenu.show(); } } @@ -379,25 +439,23 @@ public class BackgroundPlayerActivity extends AppCompatActivity repeatAlpha = 255; break; } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - repeatButton.setImageAlpha(repeatAlpha); - } else { - repeatButton.setAlpha(repeatAlpha); - } int shuffleAlpha = 255; if (!shuffled) { shuffleAlpha = 77; } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + repeatButton.setImageAlpha(repeatAlpha); shuffleButton.setImageAlpha(shuffleAlpha); } else { + repeatButton.setAlpha(repeatAlpha); shuffleButton.setAlpha(shuffleAlpha); } if (parameters != null) { - final float speed = parameters.speed; - final float pitch = parameters.pitch; + playbackSpeedButton.setText(player.formatSpeed(parameters.speed)); + playbackPitchButton.setText(player.formatPitch(parameters.pitch)); } scrollToSelected(); diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index 82fb10607..3f1d86818 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -142,6 +142,9 @@ public abstract class BasePlayer implements Player.EventListener, // Playback //////////////////////////////////////////////////////////////////////////*/ + protected static final float[] PLAYBACK_SPEEDS = {0.5f, 0.75f, 1f, 1.25f, 1.5f, 1.75f, 2f}; + protected static final float[] PLAYBACK_PITCHES = {0.8f, 0.9f, 0.95f, 1f, 1.05f, 1.1f, 1.2f}; + protected MediaSourceManager playbackManager; protected PlayQueue playQueue; @@ -862,6 +865,7 @@ public abstract class BasePlayer implements Player.EventListener, private final StringBuilder stringBuilder = new StringBuilder(); private final Formatter formatter = new Formatter(stringBuilder, Locale.getDefault()); private final NumberFormat speedFormatter = new DecimalFormat("0.##x"); + private final NumberFormat pitchFormatter = new DecimalFormat("##.##%"); // todo: merge this into Localization public String getTimeString(int milliSeconds) { @@ -880,6 +884,10 @@ public abstract class BasePlayer implements Player.EventListener, return speedFormatter.format(speed); } + protected String formatPitch(float pitch) { + return pitchFormatter.format(pitch); + } + protected void startProgressLoop() { if (progressUpdateReactor != null) progressUpdateReactor.dispose(); progressUpdateReactor = getProgressReactor(); @@ -990,11 +998,28 @@ public abstract class BasePlayer implements Player.EventListener, } public float getPlaybackSpeed() { - return simpleExoPlayer.getPlaybackParameters().speed; + return getPlaybackParameters().speed; + } + + public float getPlaybackPitch() { + return getPlaybackParameters().pitch; } public void setPlaybackSpeed(float speed) { - simpleExoPlayer.setPlaybackParameters(new PlaybackParameters(speed, 1f)); + setPlaybackParameters(speed, getPlaybackPitch()); + } + + public void setPlaybackPitch(float pitch) { + setPlaybackParameters(getPlaybackSpeed(), pitch); + } + + public PlaybackParameters getPlaybackParameters() { + final PlaybackParameters parameters = simpleExoPlayer.getPlaybackParameters(); + return parameters == null ? new PlaybackParameters(1f, 1f) : parameters; + } + + public void setPlaybackParameters(float speed, float pitch) { + simpleExoPlayer.setPlaybackParameters(new PlaybackParameters(speed, pitch)); } public int getCurrentQueueIndex() { diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java index 29df0323e..5d2ef1967 100644 --- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java @@ -103,7 +103,6 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. //////////////////////////////////////////////////////////////////////////*/ public static final int DEFAULT_CONTROLS_HIDE_TIME = 2000; // 2 Seconds - private static final float[] PLAYBACK_SPEEDS = {0.5f, 0.75f, 1f, 1.25f, 1.5f, 1.75f, 2f}; private static final TrackSelection.Factory FIXED_FACTORY = new FixedTrackSelection.Factory(); private List trackGroupInfos; diff --git a/app/src/main/res/layout/activity_background_player.xml b/app/src/main/res/layout/activity_background_player.xml index 17a0419dd..3a4a4454d 100644 --- a/app/src/main/res/layout/activity_background_player.xml +++ b/app/src/main/res/layout/activity_background_player.xml @@ -122,6 +122,21 @@ android:background="@drawable/player_controls_bg" tools:ignore="RtlHardcoded"> + + + + \ No newline at end of file