-Added fling to toss popup view when velocity is below shutdown.

-Added string for unknown content.
-Fixed NPE when UI element is touched after player shuts down in service activity.
-Fixed shuffle reset caused by position discontinuity offsets index.
-Moved some more player shared preferences to PlayerHelper.
This commit is contained in:
John Zhen Mo 2017-10-31 17:07:12 -07:00
parent 01e031e7e7
commit 38b2ffd450
5 changed files with 71 additions and 24 deletions

View File

@ -590,12 +590,12 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListen
if (DEBUG) Log.d(TAG, "onPositionDiscontinuity() called with window index = [" + newWindowIndex + "]"); if (DEBUG) Log.d(TAG, "onPositionDiscontinuity() called with window index = [" + newWindowIndex + "]");
// If the user selects a new track, then the discontinuity occurs after the index is changed. // If the user selects a new track, then the discontinuity occurs after the index is changed.
// Therefore, the only source that causes a discrepancy would be autoplay, // Therefore, the only source that causes a discrepancy would be gapless transition,
// which can only offset the current track by +1. // which can only offset the current track by +1.
if (newWindowIndex != playQueue.getIndex() && playbackManager != null) { if (newWindowIndex == playQueue.getIndex() + 1) {
playQueue.offsetIndex(+1); playQueue.offsetIndex(+1);
playbackManager.load();
} }
playbackManager.load();
} }
@Override @Override
@ -612,6 +612,8 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListen
if (simpleExoPlayer == null) return; if (simpleExoPlayer == null) return;
if (DEBUG) Log.d(TAG, "Blocking..."); if (DEBUG) Log.d(TAG, "Blocking...");
currentItem = null;
currentInfo = null;
simpleExoPlayer.stop(); simpleExoPlayer.stop();
isPrepared = false; isPrepared = false;
@ -642,8 +644,8 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListen
// Check if on wrong window // Check if on wrong window
final int currentSourceIndex = playQueue.indexOf(item); final int currentSourceIndex = playQueue.indexOf(item);
if (currentSourceIndex != playQueue.getIndex()) { if (currentSourceIndex != playQueue.getIndex()) {
throw new IllegalStateException("Play Queue may be desynchronized: item index=[" + Log.e(TAG, "Play Queue may be desynchronized: item index=[" + currentSourceIndex +
currentSourceIndex + "], queue index=[" + playQueue.getIndex() + "]"); "], queue index=[" + playQueue.getIndex() + "]");
} else if (simpleExoPlayer.getCurrentWindowIndex() != currentSourceIndex) { } else if (simpleExoPlayer.getCurrentWindowIndex() != currentSourceIndex) {
final long startPos = info != null ? info.start_position : 0; final long startPos = info != null ? info.start_position : 0;
if (DEBUG) Log.d(TAG, "Rewinding to correct window: " + currentSourceIndex + " at: " + getTimeString((int)startPos)); if (DEBUG) Log.d(TAG, "Rewinding to correct window: " + currentSourceIndex + " at: " + getTimeString((int)startPos));
@ -829,15 +831,15 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListen
} }
public String getVideoUrl() { public String getVideoUrl() {
return currentItem == null ? null : currentItem.getUrl(); return currentItem == null ? context.getString(R.string.unknown_content) : currentItem.getUrl();
} }
public String getVideoTitle() { public String getVideoTitle() {
return currentItem == null ? null : currentItem.getTitle(); return currentItem == null ? context.getString(R.string.unknown_content) : currentItem.getTitle();
} }
public String getUploaderName() { public String getUploaderName() {
return currentItem == null ? null : currentItem.getUploader(); return currentItem == null ? context.getString(R.string.unknown_content) : currentItem.getUploader();
} }
public boolean isCompleted() { public boolean isCompleted() {
@ -873,8 +875,10 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListen
} }
public PlaybackParameters getPlaybackParameters() { public PlaybackParameters getPlaybackParameters() {
final PlaybackParameters defaultParameters = new PlaybackParameters(1f, 1f);
if (simpleExoPlayer == null) return defaultParameters;
final PlaybackParameters parameters = simpleExoPlayer.getPlaybackParameters(); final PlaybackParameters parameters = simpleExoPlayer.getPlaybackParameters();
return parameters == null ? new PlaybackParameters(1f, 1f) : parameters; return parameters == null ? defaultParameters : parameters;
} }
public void setPlaybackParameters(float speed, float pitch) { public void setPlaybackParameters(float speed, float pitch) {
@ -903,7 +907,7 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListen
final int queuePos = playQueue.getIndex(); final int queuePos = playQueue.getIndex();
final long windowPos = simpleExoPlayer.getCurrentPosition(); final long windowPos = simpleExoPlayer.getCurrentPosition();
if (windowPos > 0) { if (windowPos > 0 && windowPos <= simpleExoPlayer.getDuration()) {
setRecovery(queuePos, windowPos); setRecovery(queuePos, windowPos);
} }
} }

View File

@ -65,6 +65,7 @@ import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.player.event.PlayerEventListener; import org.schabi.newpipe.player.event.PlayerEventListener;
import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.old.PlayVideoActivity; import org.schabi.newpipe.player.old.PlayVideoActivity;
import org.schabi.newpipe.player.helper.LockManager; import org.schabi.newpipe.player.helper.LockManager;
import org.schabi.newpipe.playlist.PlayQueueItem; import org.schabi.newpipe.playlist.PlayQueueItem;
@ -96,7 +97,6 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView;
public final class PopupVideoPlayer extends Service { public final class PopupVideoPlayer extends Service {
private static final String TAG = ".PopupVideoPlayer"; private static final String TAG = ".PopupVideoPlayer";
private static final boolean DEBUG = BasePlayer.DEBUG; private static final boolean DEBUG = BasePlayer.DEBUG;
private static final int SHUTDOWN_FLING_VELOCITY = 10000;
private static final int NOTIFICATION_ID = 40028922; private static final int NOTIFICATION_ID = 40028922;
public static final String ACTION_CLOSE = "org.schabi.newpipe.player.PopupVideoPlayer.CLOSE"; public static final String ACTION_CLOSE = "org.schabi.newpipe.player.PopupVideoPlayer.CLOSE";
@ -112,6 +112,9 @@ public final class PopupVideoPlayer extends Service {
private WindowManager.LayoutParams windowLayoutParams; private WindowManager.LayoutParams windowLayoutParams;
private GestureDetector gestureDetector; private GestureDetector gestureDetector;
private int shutdownFlingVelocity;
private int tossFlingVelocity;
private float screenWidth, screenHeight; private float screenWidth, screenHeight;
private float popupWidth, popupHeight; private float popupWidth, popupHeight;
@ -211,12 +214,14 @@ public final class PopupVideoPlayer extends Service {
View rootView = View.inflate(this, R.layout.player_popup, null); View rootView = View.inflate(this, R.layout.player_popup, null);
playerImpl.setup(rootView); playerImpl.setup(rootView);
shutdownFlingVelocity = PlayerHelper.getShutdownFlingVelocity(this);
tossFlingVelocity = PlayerHelper.getTossFlingVelocity(this);
updateScreenSize(); updateScreenSize();
final boolean popupRememberSizeAndPos = PlayerHelper.isRememberingPopupDimensions(this);
final float defaultSize = getResources().getDimension(R.dimen.popup_default_width);
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
boolean popupRememberSizeAndPos = sharedPreferences.getBoolean(getString(R.string.popup_remember_size_pos_key), true);
float defaultSize = getResources().getDimension(R.dimen.popup_default_width);
popupWidth = popupRememberSizeAndPos ? sharedPreferences.getFloat(POPUP_SAVED_WIDTH, defaultSize) : defaultSize; popupWidth = popupRememberSizeAndPos ? sharedPreferences.getFloat(POPUP_SAVED_WIDTH, defaultSize) : defaultSize;
final int layoutParamType = Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O ? WindowManager.LayoutParams.TYPE_PHONE : WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; final int layoutParamType = Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O ? WindowManager.LayoutParams.TYPE_PHONE : WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
@ -791,11 +796,20 @@ public final class PopupVideoPlayer extends Service {
@Override @Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (DEBUG) Log.d(TAG, "Fling velocity: dX=[" + velocityX + "], dY=[" + velocityY + "]");
if (playerImpl == null) return false; if (playerImpl == null) return false;
if (Math.abs(velocityX) > SHUTDOWN_FLING_VELOCITY) {
if (DEBUG) Log.d(TAG, "Popup close fling velocity= " + velocityX); final float absVelocityX = Math.abs(velocityX);
final float absVelocityY = Math.abs(velocityY);
if (absVelocityX > shutdownFlingVelocity) {
onClose(); onClose();
return true; return true;
} else if (Math.max(absVelocityX, absVelocityY) > tossFlingVelocity) {
if (absVelocityX > tossFlingVelocity) windowLayoutParams.x = (int) velocityX;
if (absVelocityY > tossFlingVelocity) windowLayoutParams.y = (int) velocityY;
checkPositionBounds();
windowManager.updateViewLayout(playerImpl.getRootView(), windowLayoutParams);
return true;
} }
return false; return false;
} }

View File

@ -286,6 +286,8 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override @Override
public boolean onMenuItemClick(MenuItem menuItem) { public boolean onMenuItemClick(MenuItem menuItem) {
if (player == null) return false;
player.setPlaybackSpeed(playbackSpeed); player.setPlaybackSpeed(playbackSpeed);
return true; return true;
} }
@ -304,6 +306,8 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override @Override
public boolean onMenuItemClick(MenuItem menuItem) { public boolean onMenuItemClick(MenuItem menuItem) {
if (player == null) return false;
player.setPlaybackPitch(playbackPitch); player.setPlaybackPitch(playbackPitch);
return true; return true;
} }
@ -317,6 +321,8 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
remove.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { remove.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override @Override
public boolean onMenuItemClick(MenuItem menuItem) { public boolean onMenuItemClick(MenuItem menuItem) {
if (player == null) return false;
final int index = player.getPlayQueue().indexOf(item); final int index = player.getPlayQueue().indexOf(item);
if (index != -1) player.getPlayQueue().remove(index); if (index != -1) player.getPlayQueue().remove(index);
return true; return true;
@ -349,7 +355,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
final int sourceIndex = source.getLayoutPosition(); final int sourceIndex = source.getLayoutPosition();
final int targetIndex = target.getLayoutPosition(); final int targetIndex = target.getLayoutPosition();
player.getPlayQueue().move(sourceIndex, targetIndex); if (player != null) player.getPlayQueue().move(sourceIndex, targetIndex);
return true; return true;
} }
@ -372,11 +378,13 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
return new PlayQueueItemBuilder.OnSelectedListener() { return new PlayQueueItemBuilder.OnSelectedListener() {
@Override @Override
public void selected(PlayQueueItem item, View view) { public void selected(PlayQueueItem item, View view) {
player.onSelected(item); if (player != null) player.onSelected(item);
} }
@Override @Override
public void held(PlayQueueItem item, View view) { public void held(PlayQueueItem item, View view) {
if (player == null) return;
final int index = player.getPlayQueue().indexOf(item); final int index = player.getPlayQueue().indexOf(item);
if (index != -1) buildItemPopupMenu(item, view); if (index != -1) buildItemPopupMenu(item, view);
} }
@ -403,19 +411,19 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
@Override @Override
public void onClick(View view) { public void onClick(View view) {
if (view.getId() == repeatButton.getId()) { if (view.getId() == repeatButton.getId()) {
player.onRepeatClicked(); if (player != null) player.onRepeatClicked();
} else if (view.getId() == backwardButton.getId()) { } else if (view.getId() == backwardButton.getId()) {
player.onPlayPrevious(); if (player != null) player.onPlayPrevious();
} else if (view.getId() == playPauseButton.getId()) { } else if (view.getId() == playPauseButton.getId()) {
player.onVideoPlayPause(); if (player != null) player.onVideoPlayPause();
} else if (view.getId() == forwardButton.getId()) { } else if (view.getId() == forwardButton.getId()) {
player.onPlayNext(); if (player != null) player.onPlayNext();
} else if (view.getId() == shuffleButton.getId()) { } else if (view.getId() == shuffleButton.getId()) {
player.onShuffleClicked(); if (player != null) player.onShuffleClicked();
} else if (view.getId() == playbackSpeedButton.getId()) { } else if (view.getId() == playbackSpeedButton.getId()) {
playbackSpeedPopupMenu.show(); playbackSpeedPopupMenu.show();
@ -450,7 +458,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
@Override @Override
public void onStopTrackingTouch(SeekBar seekBar) { public void onStopTrackingTouch(SeekBar seekBar) {
player.simpleExoPlayer.seekTo(seekBar.getProgress()); if (player != null) player.simpleExoPlayer.seekTo(seekBar.getProgress());
seekDisplay.setVisibility(View.GONE); seekDisplay.setVisibility(View.GONE);
seeking = false; seeking = false;
} }

View File

@ -12,6 +12,8 @@ import java.text.NumberFormat;
import java.util.Formatter; import java.util.Formatter;
import java.util.Locale; import java.util.Locale;
import javax.annotation.Nonnull;
public class PlayerHelper { public class PlayerHelper {
private PlayerHelper() {} private PlayerHelper() {}
@ -56,6 +58,10 @@ public class PlayerHelper {
return isUsingOldPlayer(context, false); return isUsingOldPlayer(context, false);
} }
public static boolean isRememberingPopupDimensions(@Nonnull final Context context) {
return isRememberingPopupDimensions(context, true);
}
public static long getPreferredCacheSize(@NonNull final Context context) { public static long getPreferredCacheSize(@NonNull final Context context) {
return 64 * 1024 * 1024L; return 64 * 1024 * 1024L;
} }
@ -83,6 +89,15 @@ public class PlayerHelper {
public static boolean isUsingDSP(@NonNull final Context context) { public static boolean isUsingDSP(@NonNull final Context context) {
return true; return true;
} }
public static int getShutdownFlingVelocity(@Nonnull final Context context) {
return 10000;
}
public static int getTossFlingVelocity(@Nonnull final Context context) {
return 2500;
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Private helpers // Private helpers
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -103,4 +118,8 @@ public class PlayerHelper {
private static boolean isUsingOldPlayer(@NonNull final Context context, final boolean b) { private static boolean isUsingOldPlayer(@NonNull final Context context, final boolean b) {
return getPreferences(context).getBoolean(context.getString(R.string.use_old_player_key), b); return getPreferences(context).getBoolean(context.getString(R.string.use_old_player_key), b);
} }
private static boolean isRememberingPopupDimensions(@Nonnull final Context context, final boolean b) {
return getPreferences(context).getBoolean(context.getString(R.string.popup_remember_size_pos_key), b);
}
} }

View File

@ -122,6 +122,8 @@
<string name="notification_channel_name">NewPipe Notification</string> <string name="notification_channel_name">NewPipe Notification</string>
<string name="notification_channel_description">Notifications for NewPipe Background and Popup Players</string> <string name="notification_channel_description">Notifications for NewPipe Background and Popup Players</string>
<string name="unknown_content">[Unknown]</string>
<!-- error strings --> <!-- error strings -->
<string name="general_error">Error</string> <string name="general_error">Error</string>
<string name="network_error">Network error</string> <string name="network_error">Network error</string>