mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 07:13:00 +00:00 
			
		
		
		
	-Changed quality resolution to persist across player.
-Updated ExoPlayer to 2.5.4. -Expanded button size in main video player play queue. -Removed Quality event. -Extracted player error strings to xml.
This commit is contained in:
		| @@ -66,7 +66,7 @@ dependencies { | |||||||
|     compile 'de.hdodenhof:circleimageview:2.1.0' |     compile 'de.hdodenhof:circleimageview:2.1.0' | ||||||
|     compile 'com.github.nirhart:parallaxscroll:1.0' |     compile 'com.github.nirhart:parallaxscroll:1.0' | ||||||
|     compile 'com.nononsenseapps:filepicker:3.0.1' |     compile 'com.nononsenseapps:filepicker:3.0.1' | ||||||
|     compile 'com.google.android.exoplayer:exoplayer:r2.5.3' |     compile 'com.google.android.exoplayer:exoplayer:r2.5.4' | ||||||
|  |  | ||||||
|     debugCompile 'com.facebook.stetho:stetho:1.5.0' |     debugCompile 'com.facebook.stetho:stetho:1.5.0' | ||||||
|     debugCompile 'com.facebook.stetho:stetho-urlconnection:1.5.0' |     debugCompile 'com.facebook.stetho:stetho-urlconnection:1.5.0' | ||||||
|   | |||||||
| @@ -788,14 +788,14 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement | |||||||
|             ((HistoryListener) activity).onVideoPlayed(currentInfo, getSelectedVideoStream()); |             ((HistoryListener) activity).onVideoPlayed(currentInfo, getSelectedVideoStream()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         final PlayQueue playQueue = new SinglePlayQueue(currentInfo, actionBarHandler.getSelectedVideoStream()); |         final PlayQueue playQueue = new SinglePlayQueue(currentInfo); | ||||||
|         final Intent intent; |         final Intent intent; | ||||||
|         if (append) { |         if (append) { | ||||||
|             Toast.makeText(activity, R.string.popup_playing_append, Toast.LENGTH_SHORT).show(); |             Toast.makeText(activity, R.string.popup_playing_append, Toast.LENGTH_SHORT).show(); | ||||||
|             intent = NavigationHelper.getPlayerEnqueueIntent(activity, PopupVideoPlayer.class, playQueue); |             intent = NavigationHelper.getPlayerEnqueueIntent(activity, PopupVideoPlayer.class, playQueue); | ||||||
|         } else { |         } else { | ||||||
|             Toast.makeText(activity, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show(); |             Toast.makeText(activity, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show(); | ||||||
|             intent = NavigationHelper.getPlayerIntent(activity, PopupVideoPlayer.class, playQueue); |             intent = NavigationHelper.getPlayerIntent(activity, PopupVideoPlayer.class, playQueue, getSelectedVideoStream().resolution); | ||||||
|         } |         } | ||||||
|         activity.startService(intent); |         activity.startService(intent); | ||||||
|     } |     } | ||||||
| @@ -866,8 +866,8 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement | |||||||
|                 || (Build.VERSION.SDK_INT < 16); |                 || (Build.VERSION.SDK_INT < 16); | ||||||
|         if (!useOldPlayer) { |         if (!useOldPlayer) { | ||||||
|             // ExoPlayer |             // ExoPlayer | ||||||
|             final PlayQueue playQueue = new SinglePlayQueue(currentInfo, actionBarHandler.getSelectedVideoStream()); |             final PlayQueue playQueue = new SinglePlayQueue(currentInfo); | ||||||
|             mIntent = NavigationHelper.getPlayerIntent(activity, MainVideoPlayer.class, playQueue); |             mIntent = NavigationHelper.getPlayerIntent(activity, MainVideoPlayer.class, playQueue, getSelectedVideoStream().resolution); | ||||||
|         } else { |         } else { | ||||||
|             // Internal Player |             // Internal Player | ||||||
|             mIntent = new Intent(activity, PlayVideoActivity.class) |             mIntent = new Intent(activity, PlayVideoActivity.class) | ||||||
|   | |||||||
| @@ -388,13 +388,23 @@ public final class BackgroundPlayer extends Service { | |||||||
|         @Override |         @Override | ||||||
|         public void onRecoverableError(Exception exception) { |         public void onRecoverableError(Exception exception) { | ||||||
|             exception.printStackTrace(); |             exception.printStackTrace(); | ||||||
|             Toast.makeText(context, "Failed to play this audio", Toast.LENGTH_SHORT).show(); |  | ||||||
|  |             if (errorToast == null) { | ||||||
|  |                 errorToast = Toast.makeText(context, R.string.player_audio_failure, Toast.LENGTH_SHORT); | ||||||
|  |                 errorToast.show(); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         @Override |         @Override | ||||||
|         public void onUnrecoverableError(Exception exception) { |         public void onUnrecoverableError(Exception exception) { | ||||||
|             exception.printStackTrace(); |             exception.printStackTrace(); | ||||||
|             Toast.makeText(context, "Unexpected error occurred", Toast.LENGTH_SHORT).show(); |  | ||||||
|  |             if (errorToast != null) { | ||||||
|  |                 errorToast.cancel(); | ||||||
|  |             } | ||||||
|  |             errorToast = Toast.makeText(context, R.string.player_unexpected_failure, Toast.LENGTH_SHORT); | ||||||
|  |             errorToast.show(); | ||||||
|  |  | ||||||
|             shutdown(); |             shutdown(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -36,6 +36,7 @@ import android.support.annotation.Nullable; | |||||||
| import android.text.TextUtils; | import android.text.TextUtils; | ||||||
| import android.util.Log; | import android.util.Log; | ||||||
| import android.view.View; | import android.view.View; | ||||||
|  | import android.widget.Toast; | ||||||
|  |  | ||||||
| import com.google.android.exoplayer2.C; | import com.google.android.exoplayer2.C; | ||||||
| import com.google.android.exoplayer2.DefaultLoadControl; | import com.google.android.exoplayer2.DefaultLoadControl; | ||||||
| @@ -125,6 +126,7 @@ public abstract class BasePlayer implements Player.EventListener, | |||||||
|     public static final String REPEAT_MODE = "repeat_mode"; |     public static final String REPEAT_MODE = "repeat_mode"; | ||||||
|     public static final String PLAYBACK_PITCH = "playback_pitch"; |     public static final String PLAYBACK_PITCH = "playback_pitch"; | ||||||
|     public static final String PLAYBACK_SPEED = "playback_speed"; |     public static final String PLAYBACK_SPEED = "playback_speed"; | ||||||
|  |     public static final String PLAYBACK_QUALITY = "playback_quality"; | ||||||
|     public static final String PLAY_QUEUE = "play_queue"; |     public static final String PLAY_QUEUE = "play_queue"; | ||||||
|     public static final String APPEND_ONLY = "append_only"; |     public static final String APPEND_ONLY = "append_only"; | ||||||
|  |  | ||||||
| @@ -141,6 +143,7 @@ public abstract class BasePlayer implements Player.EventListener, | |||||||
|     protected StreamInfo currentInfo; |     protected StreamInfo currentInfo; | ||||||
|     protected PlayQueueItem currentItem; |     protected PlayQueueItem currentItem; | ||||||
|  |  | ||||||
|  |     protected Toast errorToast; | ||||||
|     /*////////////////////////////////////////////////////////////////////////// |     /*////////////////////////////////////////////////////////////////////////// | ||||||
|     // Player |     // Player | ||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
| @@ -659,8 +662,8 @@ public abstract class BasePlayer implements Player.EventListener, | |||||||
|      * {@link ExoPlaybackException#TYPE_SOURCE TYPE_SOURCE}: <br><br> |      * {@link ExoPlaybackException#TYPE_SOURCE TYPE_SOURCE}: <br><br> | ||||||
|      * If the current {@link com.google.android.exoplayer2.Timeline.Window window} has |      * If the current {@link com.google.android.exoplayer2.Timeline.Window window} has | ||||||
|      * duration and position greater than 0, then we know the current window is working correctly |      * duration and position greater than 0, then we know the current window is working correctly | ||||||
|      * and the error is produced by transitioning into a bad window, therefore we simply increment |      * and the error is produced by transitioning into a bad window, therefore we report an error | ||||||
|      * the current index. Otherwise, we report an error to the play queue. |      * to the play queue based on if the current error can be skipped. | ||||||
|      * |      * | ||||||
|      * This is done because ExoPlayer reports the source exceptions before window is |      * This is done because ExoPlayer reports the source exceptions before window is | ||||||
|      * transitioned on seamless playback. |      * transitioned on seamless playback. | ||||||
| @@ -668,27 +671,33 @@ public abstract class BasePlayer implements Player.EventListener, | |||||||
|      * Because player error causes ExoPlayer to go back to {@link Player#STATE_IDLE STATE_IDLE}, |      * Because player error causes ExoPlayer to go back to {@link Player#STATE_IDLE STATE_IDLE}, | ||||||
|      * we reset and prepare the media source again to resume playback.<br><br> |      * we reset and prepare the media source again to resume playback.<br><br> | ||||||
|      * |      * | ||||||
|      * {@link ExoPlaybackException#TYPE_RENDERER TYPE_RENDERER} and |  | ||||||
|      * {@link ExoPlaybackException#TYPE_UNEXPECTED TYPE_UNEXPECTED}: <br><br> |      * {@link ExoPlaybackException#TYPE_UNEXPECTED TYPE_UNEXPECTED}: <br><br> | ||||||
|      * If renderer failed or unexpected exceptions occurred, treat the error as unrecoverable. |      * If a runtime error occurred, then we can try to recover it by restarting the playback | ||||||
|  |      * after setting the timestamp recovery. | ||||||
|  |      * | ||||||
|  |      * {@link ExoPlaybackException#TYPE_RENDERER TYPE_RENDERER}: <br><br> | ||||||
|  |      * If the renderer failed, treat the error as unrecoverable. | ||||||
|      * |      * | ||||||
|      * @see Player.EventListener#onPlayerError(ExoPlaybackException) |      * @see Player.EventListener#onPlayerError(ExoPlaybackException) | ||||||
|      *  */ |      *  */ | ||||||
|     @Override |     @Override | ||||||
|     public void onPlayerError(ExoPlaybackException error) { |     public void onPlayerError(ExoPlaybackException error) { | ||||||
|         if (DEBUG) Log.d(TAG, "onPlayerError() called with: error = [" + error + "]"); |         if (DEBUG) Log.d(TAG, "onPlayerError() called with: error = [" + error + "]"); | ||||||
|  |         if (errorToast != null) { | ||||||
|  |             errorToast.cancel(); | ||||||
|  |             errorToast = null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         switch (error.type) { |         switch (error.type) { | ||||||
|             case ExoPlaybackException.TYPE_SOURCE: |             case ExoPlaybackException.TYPE_SOURCE: | ||||||
|                 if (simpleExoPlayer.getDuration() < 0 || simpleExoPlayer.getCurrentPosition() < 0) { |                 final boolean skippable = simpleExoPlayer.getDuration() >= 0 && simpleExoPlayer.getCurrentPosition() >= 0; | ||||||
|                     playQueue.error(); |                 playQueue.error(skippable); | ||||||
|                 onRecoverableError(error); |                 onRecoverableError(error); | ||||||
|                 } else { |                 break; | ||||||
|                     playQueue.offsetIndex(+1); |             case ExoPlaybackException.TYPE_UNEXPECTED: | ||||||
|                 } |                 onRecoverableError(error); | ||||||
|  |                 setRecovery(); | ||||||
|                 playbackManager.reset(); |                 reload(); | ||||||
|                 playbackManager.load(); |  | ||||||
|                 break; |                 break; | ||||||
|             default: |             default: | ||||||
|                 onUnrecoverableError(error); |                 onUnrecoverableError(error); | ||||||
| @@ -883,6 +892,13 @@ public abstract class BasePlayer implements Player.EventListener, | |||||||
|         return pitchFormatter.format(pitch); |         return pitchFormatter.format(pitch); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     protected void reload() { | ||||||
|  |         if (playbackManager != null) { | ||||||
|  |             playbackManager.reset(); | ||||||
|  |             playbackManager.load(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     protected void startProgressLoop() { |     protected void startProgressLoop() { | ||||||
|         if (progressUpdateReactor != null) progressUpdateReactor.dispose(); |         if (progressUpdateReactor != null) progressUpdateReactor.dispose(); | ||||||
|         progressUpdateReactor = getProgressReactor(); |         progressUpdateReactor = getProgressReactor(); | ||||||
|   | |||||||
| @@ -344,7 +344,8 @@ public final class MainVideoPlayer extends Activity { | |||||||
|                     this.getPlayQueue(), |                     this.getPlayQueue(), | ||||||
|                     this.simpleExoPlayer.getRepeatMode(), |                     this.simpleExoPlayer.getRepeatMode(), | ||||||
|                     this.getPlaybackSpeed(), |                     this.getPlaybackSpeed(), | ||||||
|                     this.getPlaybackPitch() |                     this.getPlaybackPitch(), | ||||||
|  |                     this.getPlaybackQuality() | ||||||
|             ); |             ); | ||||||
|             context.startService(intent); |             context.startService(intent); | ||||||
|             destroyPlayer(); |             destroyPlayer(); | ||||||
| @@ -432,13 +433,23 @@ public final class MainVideoPlayer extends Activity { | |||||||
|         @Override |         @Override | ||||||
|         public void onRecoverableError(Exception exception) { |         public void onRecoverableError(Exception exception) { | ||||||
|             exception.printStackTrace(); |             exception.printStackTrace(); | ||||||
|             Toast.makeText(context, "Failed to play this video", Toast.LENGTH_SHORT).show(); |  | ||||||
|  |             if (errorToast == null) { | ||||||
|  |                 errorToast = Toast.makeText(context, R.string.player_video_failure, Toast.LENGTH_SHORT); | ||||||
|  |                 errorToast.show(); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         @Override |         @Override | ||||||
|         public void onUnrecoverableError(Exception exception) { |         public void onUnrecoverableError(Exception exception) { | ||||||
|             exception.printStackTrace(); |             exception.printStackTrace(); | ||||||
|             Toast.makeText(context, "Unexpected error occurred", Toast.LENGTH_SHORT).show(); |  | ||||||
|  |             if (errorToast != null) { | ||||||
|  |                 errorToast.cancel(); | ||||||
|  |             } | ||||||
|  |             errorToast = Toast.makeText(context, R.string.player_unexpected_failure, Toast.LENGTH_SHORT); | ||||||
|  |             errorToast.show(); | ||||||
|  |  | ||||||
|             shutdown(); |             shutdown(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -447,6 +458,12 @@ public final class MainVideoPlayer extends Activity { | |||||||
|             return ListHelper.getDefaultResolutionIndex(context, sortedVideos); |             return ListHelper.getDefaultResolutionIndex(context, sortedVideos); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         protected int getOverrideResolutionIndex(final List<VideoStream> sortedVideos, | ||||||
|  |                                                  final String playbackQuality) { | ||||||
|  |             return ListHelper.getDefaultResolutionIndex(context, sortedVideos, playbackQuality); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         /*////////////////////////////////////////////////////////////////////////// |         /*////////////////////////////////////////////////////////////////////////// | ||||||
|         // States |         // States | ||||||
|         //////////////////////////////////////////////////////////////////////////*/ |         //////////////////////////////////////////////////////////////////////////*/ | ||||||
|   | |||||||
| @@ -441,7 +441,8 @@ public final class PopupVideoPlayer extends Service { | |||||||
|                         this.getPlayQueue(), |                         this.getPlayQueue(), | ||||||
|                         this.simpleExoPlayer.getRepeatMode(), |                         this.simpleExoPlayer.getRepeatMode(), | ||||||
|                         this.getPlaybackSpeed(), |                         this.getPlaybackSpeed(), | ||||||
|                         this.getPlaybackPitch() |                         this.getPlaybackPitch(), | ||||||
|  |                         this.getPlaybackQuality() | ||||||
|                 ); |                 ); | ||||||
|                 if (!isStartedFromNewPipe()) intent.putExtra(VideoPlayer.STARTED_FROM_NEWPIPE, false); |                 if (!isStartedFromNewPipe()) intent.putExtra(VideoPlayer.STARTED_FROM_NEWPIPE, false); | ||||||
|                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||||
| @@ -468,13 +469,23 @@ public final class PopupVideoPlayer extends Service { | |||||||
|         @Override |         @Override | ||||||
|         public void onRecoverableError(Exception exception) { |         public void onRecoverableError(Exception exception) { | ||||||
|             exception.printStackTrace(); |             exception.printStackTrace(); | ||||||
|             Toast.makeText(context, "Failed to play this video", Toast.LENGTH_SHORT).show(); |  | ||||||
|  |             if (errorToast == null) { | ||||||
|  |                 errorToast = Toast.makeText(context, R.string.player_video_failure, Toast.LENGTH_SHORT); | ||||||
|  |                 errorToast.show(); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         @Override |         @Override | ||||||
|         public void onUnrecoverableError(Exception exception) { |         public void onUnrecoverableError(Exception exception) { | ||||||
|             exception.printStackTrace(); |             exception.printStackTrace(); | ||||||
|             Toast.makeText(context, "Unexpected error occurred", Toast.LENGTH_SHORT).show(); |  | ||||||
|  |             if (errorToast != null) { | ||||||
|  |                 errorToast.cancel(); | ||||||
|  |             } | ||||||
|  |             errorToast = Toast.makeText(context, R.string.player_unexpected_failure, Toast.LENGTH_SHORT); | ||||||
|  |             errorToast.show(); | ||||||
|  |  | ||||||
|             shutdown(); |             shutdown(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -503,6 +514,12 @@ public final class PopupVideoPlayer extends Service { | |||||||
|             return ListHelper.getPopupDefaultResolutionIndex(context, sortedVideos); |             return ListHelper.getPopupDefaultResolutionIndex(context, sortedVideos); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         protected int getOverrideResolutionIndex(final List<VideoStream> sortedVideos, | ||||||
|  |                                                  final String playbackQuality) { | ||||||
|  |             return ListHelper.getPopupDefaultResolutionIndex(context, sortedVideos, playbackQuality); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         /*////////////////////////////////////////////////////////////////////////// |         /*////////////////////////////////////////////////////////////////////////// | ||||||
|         // Activity Event Listener |         // Activity Event Listener | ||||||
|         //////////////////////////////////////////////////////////////////////////*/ |         //////////////////////////////////////////////////////////////////////////*/ | ||||||
|   | |||||||
| @@ -25,6 +25,7 @@ import android.animation.ObjectAnimator; | |||||||
| import android.animation.PropertyValuesHolder; | import android.animation.PropertyValuesHolder; | ||||||
| import android.animation.ValueAnimator; | import android.animation.ValueAnimator; | ||||||
| import android.content.Context; | import android.content.Context; | ||||||
|  | import android.content.Intent; | ||||||
| import android.graphics.Bitmap; | import android.graphics.Bitmap; | ||||||
| import android.graphics.Color; | import android.graphics.Color; | ||||||
| import android.graphics.PorterDuff; | import android.graphics.PorterDuff; | ||||||
| @@ -48,6 +49,7 @@ import android.widget.TextView; | |||||||
| import com.google.android.exoplayer2.C; | import com.google.android.exoplayer2.C; | ||||||
| import com.google.android.exoplayer2.Player; | import com.google.android.exoplayer2.Player; | ||||||
| import com.google.android.exoplayer2.SimpleExoPlayer; | import com.google.android.exoplayer2.SimpleExoPlayer; | ||||||
|  | import com.google.android.exoplayer2.source.ConcatenatingMediaSource; | ||||||
| import com.google.android.exoplayer2.source.MediaSource; | import com.google.android.exoplayer2.source.MediaSource; | ||||||
| import com.google.android.exoplayer2.source.MergingMediaSource; | import com.google.android.exoplayer2.source.MergingMediaSource; | ||||||
| import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; | import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; | ||||||
| @@ -82,15 +84,17 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. | |||||||
|  |  | ||||||
|     public static final String STARTED_FROM_NEWPIPE = "started_from_newpipe"; |     public static final String STARTED_FROM_NEWPIPE = "started_from_newpipe"; | ||||||
|  |  | ||||||
|     private ArrayList<VideoStream> availableStreams; |  | ||||||
|     private int selectedStreamIndex; |  | ||||||
|  |  | ||||||
|     /*////////////////////////////////////////////////////////////////////////// |     /*////////////////////////////////////////////////////////////////////////// | ||||||
|     // Player |     // Player | ||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
|  |  | ||||||
|     public static final int DEFAULT_CONTROLS_HIDE_TIME = 2000;  // 2 Seconds |     public static final int DEFAULT_CONTROLS_HIDE_TIME = 2000;  // 2 Seconds | ||||||
|  |  | ||||||
|  |     private ArrayList<VideoStream> availableStreams; | ||||||
|  |     private int selectedStreamIndex; | ||||||
|  |  | ||||||
|  |     protected String playbackQuality; | ||||||
|  |  | ||||||
|     private boolean startedFromNewPipe = true; |     private boolean startedFromNewPipe = true; | ||||||
|     protected boolean wasPlaying = false; |     protected boolean wasPlaying = false; | ||||||
|  |  | ||||||
| @@ -125,7 +129,6 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. | |||||||
|     private Handler controlsVisibilityHandler = new Handler(); |     private Handler controlsVisibilityHandler = new Handler(); | ||||||
|  |  | ||||||
|     private boolean isSomePopupMenuVisible = false; |     private boolean isSomePopupMenuVisible = false; | ||||||
|     private boolean qualityChanged = false; |  | ||||||
|     private int qualityPopupMenuGroupId = 69; |     private int qualityPopupMenuGroupId = 69; | ||||||
|     private PopupMenu qualityPopupMenu; |     private PopupMenu qualityPopupMenu; | ||||||
|  |  | ||||||
| @@ -197,6 +200,17 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void handleIntent(final Intent intent) { | ||||||
|  |         if (intent == null) return; | ||||||
|  |  | ||||||
|  |         if (intent.hasExtra(PLAYBACK_QUALITY)) { | ||||||
|  |             setPlaybackQuality(intent.getStringExtra(PLAYBACK_QUALITY)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         super.handleIntent(intent); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /*////////////////////////////////////////////////////////////////////////// |     /*////////////////////////////////////////////////////////////////////////// | ||||||
|     // UI Builders |     // UI Builders | ||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
| @@ -232,6 +246,8 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. | |||||||
|  |  | ||||||
|     protected abstract int getDefaultResolutionIndex(final List<VideoStream> sortedVideos); |     protected abstract int getDefaultResolutionIndex(final List<VideoStream> sortedVideos); | ||||||
|  |  | ||||||
|  |     protected abstract int getOverrideResolutionIndex(final List<VideoStream> sortedVideos, final String playbackQuality); | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void sync(@NonNull final PlayQueueItem item, @Nullable final StreamInfo info) { |     public void sync(@NonNull final PlayQueueItem item, @Nullable final StreamInfo info) { | ||||||
|         super.sync(item, info); |         super.sync(item, info); | ||||||
| @@ -241,11 +257,10 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. | |||||||
|         if (info != null) { |         if (info != null) { | ||||||
|             final List<VideoStream> videos = ListHelper.getSortedStreamVideosList(context, info.video_streams, info.video_only_streams, false); |             final List<VideoStream> videos = ListHelper.getSortedStreamVideosList(context, info.video_streams, info.video_only_streams, false); | ||||||
|             availableStreams = new ArrayList<>(videos); |             availableStreams = new ArrayList<>(videos); | ||||||
|             final int qualityIndex = item.getQualityIndex(); |             if (playbackQuality == null) { | ||||||
|             if (qualityIndex == PlayQueueItem.DEFAULT_QUALITY) { |  | ||||||
|                 selectedStreamIndex = getDefaultResolutionIndex(videos); |                 selectedStreamIndex = getDefaultResolutionIndex(videos); | ||||||
|             } else { |             } else { | ||||||
|                 selectedStreamIndex = qualityIndex; |                 selectedStreamIndex = getOverrideResolutionIndex(videos, getPlaybackQuality()); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             buildQualityMenu(); |             buildQualityMenu(); | ||||||
| @@ -255,17 +270,17 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|     public MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info) { |     public MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info) { | ||||||
|         final List<VideoStream> videos = ListHelper.getSortedStreamVideosList(context, info.video_streams, info.video_only_streams, false); |         final List<VideoStream> videos = ListHelper.getSortedStreamVideosList(context, info.video_streams, info.video_only_streams, false); | ||||||
|         final int sortedStreamsIndex = item.getQualityIndex(); |  | ||||||
|         if (videos.isEmpty() || sortedStreamsIndex >= videos.size()) return null; |  | ||||||
|  |  | ||||||
|         final VideoStream video; |         final VideoStream video; | ||||||
|         if (sortedStreamsIndex == PlayQueueItem.DEFAULT_QUALITY) { |         if (playbackQuality == null) { | ||||||
|             final int index = getDefaultResolutionIndex(videos); |             final int index = getDefaultResolutionIndex(videos); | ||||||
|             video = videos.get(index); |             video = videos.get(index); | ||||||
|         } else { |         } else { | ||||||
|             video = videos.get(sortedStreamsIndex); |             final int index = getOverrideResolutionIndex(videos, getPlaybackQuality()); | ||||||
|  |             video = videos.get(index); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         final MediaSource streamSource = buildMediaSource(video.url, MediaFormat.getSuffixById(video.format)); |         final MediaSource streamSource = buildMediaSource(video.url, MediaFormat.getSuffixById(video.format)); | ||||||
| @@ -455,10 +470,15 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. | |||||||
|             Log.d(TAG, "onMenuItemClick() called with: menuItem = [" + menuItem + "], menuItem.getItemId = [" + menuItem.getItemId() + "]"); |             Log.d(TAG, "onMenuItemClick() called with: menuItem = [" + menuItem + "], menuItem.getItemId = [" + menuItem.getItemId() + "]"); | ||||||
|  |  | ||||||
|         if (qualityPopupMenuGroupId == menuItem.getGroupId()) { |         if (qualityPopupMenuGroupId == menuItem.getGroupId()) { | ||||||
|             if (selectedStreamIndex == menuItem.getItemId()) return true; |             final int menuItemIndex = menuItem.getItemId(); | ||||||
|  |             if (selectedStreamIndex == menuItemIndex || | ||||||
|  |                     availableStreams == null || availableStreams.size() <= menuItemIndex) return true; | ||||||
|  |  | ||||||
|  |             final String oldResolution = getPlaybackQuality(); | ||||||
|  |             final String newResolution = availableStreams.get(menuItemIndex).resolution; | ||||||
|             setRecovery(); |             setRecovery(); | ||||||
|             playQueue.setQuality(playQueue.getIndex(), menuItem.getItemId()); |             setPlaybackQuality(newResolution); | ||||||
|  |             reload(); | ||||||
|  |  | ||||||
|             qualityTextView.setText(menuItem.getTitle()); |             qualityTextView.setText(menuItem.getTitle()); | ||||||
|             return true; |             return true; | ||||||
| @@ -489,8 +509,9 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. | |||||||
|         isSomePopupMenuVisible = true; |         isSomePopupMenuVisible = true; | ||||||
|         showControls(300); |         showControls(300); | ||||||
|  |  | ||||||
|         VideoStream videoStream = getSelectedVideoStream(); |         final VideoStream videoStream = getSelectedVideoStream(); | ||||||
|         qualityTextView.setText(MediaFormat.getNameById(videoStream.format) + " " + videoStream.resolution); |         final String qualityText = MediaFormat.getNameById(videoStream.format) + " " + videoStream.resolution; | ||||||
|  |         qualityTextView.setText(qualityText); | ||||||
|         wasPlaying = simpleExoPlayer.getPlayWhenReady(); |         wasPlaying = simpleExoPlayer.getPlayWhenReady(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -648,6 +669,14 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. | |||||||
|     // Getters and Setters |     // Getters and Setters | ||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
|  |  | ||||||
|  |     public void setPlaybackQuality(final String quality) { | ||||||
|  |         this.playbackQuality = quality; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public String getPlaybackQuality() { | ||||||
|  |         return playbackQuality; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public AspectRatioFrameLayout getAspectRatioFrameLayout() { |     public AspectRatioFrameLayout getAspectRatioFrameLayout() { | ||||||
|         return aspectRatioFrameLayout; |         return aspectRatioFrameLayout; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -158,8 +158,8 @@ public class MediaSourceManager implements DeferredMediaSource.Callback { | |||||||
|         // why no pattern matching in Java =( |         // why no pattern matching in Java =( | ||||||
|         switch (event.type()) { |         switch (event.type()) { | ||||||
|             case INIT: |             case INIT: | ||||||
|             case QUALITY: |  | ||||||
|             case REORDER: |             case REORDER: | ||||||
|  |             case ERROR: | ||||||
|                 reset(); |                 reset(); | ||||||
|                 break; |                 break; | ||||||
|             case APPEND: |             case APPEND: | ||||||
| @@ -177,7 +177,6 @@ public class MediaSourceManager implements DeferredMediaSource.Callback { | |||||||
|                 final MoveEvent moveEvent = (MoveEvent) event; |                 final MoveEvent moveEvent = (MoveEvent) event; | ||||||
|                 move(moveEvent.getFromIndex(), moveEvent.getToIndex()); |                 move(moveEvent.getFromIndex(), moveEvent.getToIndex()); | ||||||
|                 break; |                 break; | ||||||
|             case ERROR: |  | ||||||
|             case RECOVERY: |             case RECOVERY: | ||||||
|             default: |             default: | ||||||
|                 break; |                 break; | ||||||
|   | |||||||
| @@ -14,7 +14,6 @@ import org.schabi.newpipe.playlist.events.RecoveryEvent; | |||||||
| import org.schabi.newpipe.playlist.events.RemoveEvent; | import org.schabi.newpipe.playlist.events.RemoveEvent; | ||||||
| import org.schabi.newpipe.playlist.events.ReorderEvent; | import org.schabi.newpipe.playlist.events.ReorderEvent; | ||||||
| import org.schabi.newpipe.playlist.events.SelectEvent; | import org.schabi.newpipe.playlist.events.SelectEvent; | ||||||
| import org.schabi.newpipe.playlist.events.QualityEvent; |  | ||||||
|  |  | ||||||
| import java.io.Serializable; | import java.io.Serializable; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| @@ -247,15 +246,22 @@ public abstract class PlayQueue implements Serializable { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Report an exception for the item at the current index in order to remove it. |      * Report an exception for the item at the current index in order and the course of action: | ||||||
|  |      * if the error can be skipped or the current item should be removed. | ||||||
|      * |      * | ||||||
|      * This is done as a separate event as the underlying manager may have |      * This is done as a separate event as the underlying manager may have | ||||||
|      * different implementation regarding exceptions. |      * different implementation regarding exceptions. | ||||||
|      * */ |      * */ | ||||||
|     public synchronized void error() { |     public synchronized void error(final boolean skippable) { | ||||||
|         final int index = getIndex(); |         final int index = getIndex(); | ||||||
|  |  | ||||||
|  |         if (skippable) { | ||||||
|  |             queueIndex.incrementAndGet(); | ||||||
|  |         } else { | ||||||
|             removeInternal(index); |             removeInternal(index); | ||||||
|         broadcast(new ErrorEvent(index)); |         } | ||||||
|  |  | ||||||
|  |         broadcast(new ErrorEvent(index, skippable)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private synchronized void removeInternal(final int index) { |     private synchronized void removeInternal(final int index) { | ||||||
| @@ -301,21 +307,6 @@ public abstract class PlayQueue implements Serializable { | |||||||
|         broadcast(new MoveEvent(source, target)); |         broadcast(new MoveEvent(source, target)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Updates the quality index at the given item index. |  | ||||||
|      * |  | ||||||
|      * Broadcasts an update event, signalling to all recipients that they should reset. |  | ||||||
|      * */ |  | ||||||
|     public synchronized void setQuality(final int queueIndex, final int qualityIndex) { |  | ||||||
|         if (queueIndex < 0 || queueIndex >= streams.size()) return; |  | ||||||
|  |  | ||||||
|         final PlayQueueItem item = streams.get(queueIndex); |  | ||||||
|         final int oldQualityIndex = item.getQualityIndex(); |  | ||||||
|  |  | ||||||
|         item.setQualityIndex(qualityIndex); |  | ||||||
|         broadcast(new QualityEvent(queueIndex, oldQualityIndex, qualityIndex)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Sets the recovery record of the item at the index. |      * Sets the recovery record of the item at the index. | ||||||
|      * |      * | ||||||
|   | |||||||
| @@ -102,7 +102,6 @@ public class PlayQueueAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold | |||||||
|     private void onPlayQueueChanged(final PlayQueueEvent message) { |     private void onPlayQueueChanged(final PlayQueueEvent message) { | ||||||
|         switch (message.type()) { |         switch (message.type()) { | ||||||
|             case RECOVERY: |             case RECOVERY: | ||||||
|             case QUALITY: |  | ||||||
|                 // Do nothing. |                 // Do nothing. | ||||||
|                 break; |                 break; | ||||||
|             case SELECT: |             case SELECT: | ||||||
| @@ -116,12 +115,14 @@ public class PlayQueueAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold | |||||||
|                 break; |                 break; | ||||||
|             case ERROR: |             case ERROR: | ||||||
|                 final ErrorEvent errorEvent = (ErrorEvent) message; |                 final ErrorEvent errorEvent = (ErrorEvent) message; | ||||||
|                 notifyItemRangeRemoved(errorEvent.index(), 1); |                 if (!errorEvent.isSkippable()) { | ||||||
|  |                     notifyItemRemoved(errorEvent.index()); | ||||||
|  |                 } | ||||||
|                 notifyItemChanged(errorEvent.index()); |                 notifyItemChanged(errorEvent.index()); | ||||||
|                 break; |                 break; | ||||||
|             case REMOVE: |             case REMOVE: | ||||||
|                 final RemoveEvent removeEvent = (RemoveEvent) message; |                 final RemoveEvent removeEvent = (RemoveEvent) message; | ||||||
|                 notifyItemRangeRemoved(removeEvent.index(), 1); |                 notifyItemRemoved(removeEvent.index()); | ||||||
|                 notifyItemChanged(removeEvent.index()); |                 notifyItemChanged(removeEvent.index()); | ||||||
|                 break; |                 break; | ||||||
|             case MOVE: |             case MOVE: | ||||||
|   | |||||||
| @@ -15,7 +15,6 @@ import io.reactivex.functions.Consumer; | |||||||
| import io.reactivex.schedulers.Schedulers; | import io.reactivex.schedulers.Schedulers; | ||||||
|  |  | ||||||
| public class PlayQueueItem implements Serializable { | public class PlayQueueItem implements Serializable { | ||||||
|     final public static int DEFAULT_QUALITY = Integer.MIN_VALUE; |  | ||||||
|     final public static long RECOVERY_UNSET = Long.MIN_VALUE; |     final public static long RECOVERY_UNSET = Long.MIN_VALUE; | ||||||
|  |  | ||||||
|     final private String title; |     final private String title; | ||||||
| @@ -25,7 +24,6 @@ public class PlayQueueItem implements Serializable { | |||||||
|     final private String thumbnailUrl; |     final private String thumbnailUrl; | ||||||
|     final private String uploader; |     final private String uploader; | ||||||
|  |  | ||||||
|     private int qualityIndex; |  | ||||||
|     private long recoveryPosition; |     private long recoveryPosition; | ||||||
|     private Throwable error; |     private Throwable error; | ||||||
|  |  | ||||||
| @@ -36,11 +34,6 @@ public class PlayQueueItem implements Serializable { | |||||||
|         this.stream = Single.just(info); |         this.stream = Single.just(info); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     PlayQueueItem(@NonNull final StreamInfo info, final int qualityIndex) { |  | ||||||
|         this(info); |  | ||||||
|         this.qualityIndex = qualityIndex; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     PlayQueueItem(@NonNull final StreamInfoItem item) { |     PlayQueueItem(@NonNull final StreamInfoItem item) { | ||||||
|         this(item.name, item.url, item.service_id, item.duration, item.thumbnail_url, item.uploader_name); |         this(item.name, item.url, item.service_id, item.duration, item.thumbnail_url, item.uploader_name); | ||||||
|     } |     } | ||||||
| @@ -54,7 +47,6 @@ public class PlayQueueItem implements Serializable { | |||||||
|         this.thumbnailUrl = thumbnailUrl; |         this.thumbnailUrl = thumbnailUrl; | ||||||
|         this.uploader = uploader; |         this.uploader = uploader; | ||||||
|  |  | ||||||
|         this.qualityIndex = DEFAULT_QUALITY; |  | ||||||
|         this.recoveryPosition = RECOVERY_UNSET; |         this.recoveryPosition = RECOVERY_UNSET; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -86,10 +78,6 @@ public class PlayQueueItem implements Serializable { | |||||||
|         return uploader; |         return uploader; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public int getQualityIndex() { |  | ||||||
|         return qualityIndex; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public long getRecoveryPosition() { |     public long getRecoveryPosition() { | ||||||
|         return recoveryPosition; |         return recoveryPosition; | ||||||
|     } |     } | ||||||
| @@ -123,10 +111,6 @@ public class PlayQueueItem implements Serializable { | |||||||
|     // Item States, keep external access out |     // Item States, keep external access out | ||||||
|     //////////////////////////////////////////////////////////////////////////// |     //////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
|     /*package-private*/ void setQualityIndex(final int qualityIndex) { |  | ||||||
|         this.qualityIndex = qualityIndex; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /*package-private*/ void setRecoveryPosition(final long recoveryPosition) { |     /*package-private*/ void setRecoveryPosition(final long recoveryPosition) { | ||||||
|         this.recoveryPosition = recoveryPosition; |         this.recoveryPosition = recoveryPosition; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -9,10 +9,6 @@ public final class SinglePlayQueue extends PlayQueue { | |||||||
|         super(0, Collections.singletonList(new PlayQueueItem(info))); |         super(0, Collections.singletonList(new PlayQueueItem(info))); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public SinglePlayQueue(final StreamInfo info, final int qualityIndex) { |  | ||||||
|         super(0, Collections.singletonList(new PlayQueueItem(info, qualityIndex))); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public boolean isComplete() { |     public boolean isComplete() { | ||||||
|         return true; |         return true; | ||||||
|   | |||||||
| @@ -3,17 +3,23 @@ package org.schabi.newpipe.playlist.events; | |||||||
|  |  | ||||||
| public class ErrorEvent implements PlayQueueEvent { | public class ErrorEvent implements PlayQueueEvent { | ||||||
|     final private int index; |     final private int index; | ||||||
|  |     final private boolean skippable; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public PlayQueueEventType type() { |     public PlayQueueEventType type() { | ||||||
|         return PlayQueueEventType.ERROR; |         return PlayQueueEventType.ERROR; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public ErrorEvent(final int index) { |     public ErrorEvent(final int index, final boolean skippable) { | ||||||
|         this.index = index; |         this.index = index; | ||||||
|  |         this.skippable = skippable; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public int index() { |     public int index() { | ||||||
|         return index; |         return index; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public boolean isSkippable() { | ||||||
|  |         return skippable; | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -18,9 +18,6 @@ public enum PlayQueueEventType { | |||||||
|     // sent when queue is shuffled |     // sent when queue is shuffled | ||||||
|     REORDER, |     REORDER, | ||||||
|  |  | ||||||
|     // sent when quality index is set on a stream |  | ||||||
|     QUALITY, |  | ||||||
|  |  | ||||||
|     // sent when recovery record is set on a stream |     // sent when recovery record is set on a stream | ||||||
|     RECOVERY, |     RECOVERY, | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,31 +0,0 @@ | |||||||
| package org.schabi.newpipe.playlist.events; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| public class QualityEvent implements PlayQueueEvent { |  | ||||||
|     final private int streamIndex; |  | ||||||
|     final private int oldQualityIndex; |  | ||||||
|     final private int newQualityIndex; |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public PlayQueueEventType type() { |  | ||||||
|         return PlayQueueEventType.QUALITY; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public QualityEvent(final int streamIndex, final int oldQualityIndex, final int newQualityIndex) { |  | ||||||
|         this.streamIndex = streamIndex; |  | ||||||
|         this.oldQualityIndex = oldQualityIndex; |  | ||||||
|         this.newQualityIndex = newQualityIndex; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public int getStreamIndex() { |  | ||||||
|         return streamIndex; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public int getOldQualityIndex() { |  | ||||||
|         return oldQualityIndex; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public int getNewQualityIndex() { |  | ||||||
|         return newQualityIndex; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -56,6 +56,13 @@ public final class ListHelper { | |||||||
|         if (defaultPreferences == null) return 0; |         if (defaultPreferences == null) return 0; | ||||||
|  |  | ||||||
|         String defaultResolution = defaultPreferences.getString(context.getString(R.string.default_resolution_key), context.getString(R.string.default_resolution_value)); |         String defaultResolution = defaultPreferences.getString(context.getString(R.string.default_resolution_key), context.getString(R.string.default_resolution_value)); | ||||||
|  |         return getDefaultResolutionIndex(context, videoStreams, defaultResolution); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @see #getDefaultResolutionIndex(String, String, MediaFormat, List) | ||||||
|  |      */ | ||||||
|  |     public static int getDefaultResolutionIndex(Context context, List<VideoStream> videoStreams, String defaultResolution) { | ||||||
|         return getDefaultResolutionWithDefaultFormat(context, defaultResolution, videoStreams); |         return getDefaultResolutionWithDefaultFormat(context, defaultResolution, videoStreams); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -67,6 +74,13 @@ public final class ListHelper { | |||||||
|         if (defaultPreferences == null) return 0; |         if (defaultPreferences == null) return 0; | ||||||
|  |  | ||||||
|         String defaultResolution = defaultPreferences.getString(context.getString(R.string.default_popup_resolution_key), context.getString(R.string.default_popup_resolution_value)); |         String defaultResolution = defaultPreferences.getString(context.getString(R.string.default_popup_resolution_key), context.getString(R.string.default_popup_resolution_value)); | ||||||
|  |         return getPopupDefaultResolutionIndex(context, videoStreams, defaultResolution); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @see #getDefaultResolutionIndex(String, String, MediaFormat, List) | ||||||
|  |      */ | ||||||
|  |     public static int getPopupDefaultResolutionIndex(Context context, List<VideoStream> videoStreams, String defaultResolution) { | ||||||
|         return getDefaultResolutionWithDefaultFormat(context, defaultResolution, videoStreams); |         return getDefaultResolutionWithDefaultFormat(context, defaultResolution, videoStreams); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -39,21 +39,19 @@ public class NavigationHelper { | |||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
|     public static Intent getPlayerIntent(final Context context, |     public static Intent getPlayerIntent(final Context context, | ||||||
|                                          final Class targetClazz, |                                          final Class targetClazz, | ||||||
|                                          final PlayQueue playQueue) { |                                          final PlayQueue playQueue, | ||||||
|         return new Intent(context, targetClazz) |                                          final String quality) { | ||||||
|  |         Intent intent = new Intent(context, targetClazz) | ||||||
|                 .putExtra(VideoPlayer.PLAY_QUEUE, playQueue); |                 .putExtra(VideoPlayer.PLAY_QUEUE, playQueue); | ||||||
|  |         if (quality != null) intent.putExtra(VideoPlayer.PLAYBACK_QUALITY, quality); | ||||||
|  |  | ||||||
|  |         return intent; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static Intent getPlayerIntent(final Context context, |     public static Intent getPlayerIntent(final Context context, | ||||||
|                                          final Class targetClazz, |                                          final Class targetClazz, | ||||||
|                                          final PlayQueue playQueue, |                                          final PlayQueue playQueue) { | ||||||
|                                          final int repeatMode, |         return getPlayerIntent(context, targetClazz, playQueue, null); | ||||||
|                                          final float playbackSpeed, |  | ||||||
|                                          final float playbackPitch) { |  | ||||||
|         return getPlayerIntent(context, targetClazz, playQueue) |  | ||||||
|                 .putExtra(BasePlayer.REPEAT_MODE, repeatMode) |  | ||||||
|                 .putExtra(BasePlayer.PLAYBACK_SPEED, playbackSpeed) |  | ||||||
|                 .putExtra(BasePlayer.PLAYBACK_PITCH, playbackPitch); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static Intent getPlayerEnqueueIntent(final Context context, |     public static Intent getPlayerEnqueueIntent(final Context context, | ||||||
| @@ -63,6 +61,19 @@ public class NavigationHelper { | |||||||
|                 .putExtra(BasePlayer.APPEND_ONLY, true); |                 .putExtra(BasePlayer.APPEND_ONLY, true); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public static Intent getPlayerIntent(final Context context, | ||||||
|  |                                          final Class targetClazz, | ||||||
|  |                                          final PlayQueue playQueue, | ||||||
|  |                                          final int repeatMode, | ||||||
|  |                                          final float playbackSpeed, | ||||||
|  |                                          final float playbackPitch, | ||||||
|  |                                          final String playbackQuality) { | ||||||
|  |         return getPlayerIntent(context, targetClazz, playQueue, playbackQuality) | ||||||
|  |                 .putExtra(BasePlayer.REPEAT_MODE, repeatMode) | ||||||
|  |                 .putExtra(BasePlayer.PLAYBACK_SPEED, playbackSpeed) | ||||||
|  |                 .putExtra(BasePlayer.PLAYBACK_PITCH, playbackPitch); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /*////////////////////////////////////////////////////////////////////////// |     /*////////////////////////////////////////////////////////////////////////// | ||||||
|     // Through FragmentManager |     // Through FragmentManager | ||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
|   | |||||||
| @@ -57,13 +57,14 @@ | |||||||
|  |  | ||||||
|             <ImageButton |             <ImageButton | ||||||
|                 android:id="@+id/playQueueClose" |                 android:id="@+id/playQueueClose" | ||||||
|                 android:layout_width="25dp" |                 android:layout_width="50dp" | ||||||
|                 android:layout_height="25dp" |                 android:layout_height="50dp" | ||||||
|                 android:layout_centerVertical="true" |                 android:layout_centerVertical="true" | ||||||
|                 android:layout_alignParentRight="true" |                 android:layout_alignParentRight="true" | ||||||
|                 android:layout_alignParentEnd="true" |                 android:layout_alignParentEnd="true" | ||||||
|                 android:layout_marginRight="40dp" |                 android:layout_marginRight="40dp" | ||||||
|                 android:layout_marginEnd="40dp" |                 android:layout_marginEnd="40dp" | ||||||
|  |                 android:padding="10dp" | ||||||
|                 android:clickable="true" |                 android:clickable="true" | ||||||
|                 android:focusable="true" |                 android:focusable="true" | ||||||
|                 android:scaleType="fitXY" |                 android:scaleType="fitXY" | ||||||
| @@ -73,13 +74,14 @@ | |||||||
|  |  | ||||||
|             <ImageButton |             <ImageButton | ||||||
|                 android:id="@+id/repeatButton" |                 android:id="@+id/repeatButton" | ||||||
|                 android:layout_width="25dp" |                 android:layout_width="50dp" | ||||||
|                 android:layout_height="25dp" |                 android:layout_height="50dp" | ||||||
|                 android:layout_centerVertical="true" |                 android:layout_centerVertical="true" | ||||||
|                 android:layout_alignParentLeft="true" |                 android:layout_alignParentLeft="true" | ||||||
|                 android:layout_alignParentStart="true" |                 android:layout_alignParentStart="true" | ||||||
|                 android:layout_marginLeft="40dp" |                 android:layout_marginLeft="40dp" | ||||||
|                 android:layout_marginStart="40dp" |                 android:layout_marginStart="40dp" | ||||||
|  |                 android:padding="10dp" | ||||||
|                 android:clickable="true" |                 android:clickable="true" | ||||||
|                 android:focusable="true" |                 android:focusable="true" | ||||||
|                 android:scaleType="fitXY" |                 android:scaleType="fitXY" | ||||||
| @@ -89,12 +91,11 @@ | |||||||
|  |  | ||||||
|             <ImageButton |             <ImageButton | ||||||
|                 android:id="@+id/shuffleButton" |                 android:id="@+id/shuffleButton" | ||||||
|                 android:layout_width="25dp" |                 android:layout_width="50dp" | ||||||
|                 android:layout_height="25dp" |                 android:layout_height="50dp" | ||||||
|                 android:layout_centerVertical="true" |                 android:layout_centerVertical="true" | ||||||
|                 android:layout_toRightOf="@id/repeatButton" |                 android:layout_toRightOf="@id/repeatButton" | ||||||
|                 android:layout_marginLeft="15dp" |                 android:padding="10dp" | ||||||
|                 android:layout_marginStart="15dp" |  | ||||||
|                 android:clickable="true" |                 android:clickable="true" | ||||||
|                 android:focusable="true" |                 android:focusable="true" | ||||||
|                 android:scaleType="fitXY" |                 android:scaleType="fitXY" | ||||||
| @@ -301,7 +302,9 @@ | |||||||
|             android:layout_width="100dp" |             android:layout_width="100dp" | ||||||
|             android:layout_height="100dp" |             android:layout_height="100dp" | ||||||
|             android:layout_centerInParent="true" |             android:layout_centerInParent="true" | ||||||
|             android:background="#00000000" |             android:clickable="true" | ||||||
|  |             android:focusable="true" | ||||||
|  |             android:background="?attr/selectableItemBackgroundBorderless" | ||||||
|             android:scaleType="fitXY" |             android:scaleType="fitXY" | ||||||
|             android:src="@drawable/ic_pause_white" |             android:src="@drawable/ic_pause_white" | ||||||
|             tools:ignore="ContentDescription"/> |             tools:ignore="ContentDescription"/> | ||||||
| @@ -315,7 +318,9 @@ | |||||||
|             android:layout_centerInParent="true" |             android:layout_centerInParent="true" | ||||||
|             android:layout_toLeftOf="@id/playPauseButton" |             android:layout_toLeftOf="@id/playPauseButton" | ||||||
|             android:layout_toStartOf="@id/playPauseButton" |             android:layout_toStartOf="@id/playPauseButton" | ||||||
|             android:background="#00000000" |             android:clickable="true" | ||||||
|  |             android:focusable="true" | ||||||
|  |             android:background="?attr/selectableItemBackgroundBorderless" | ||||||
|             android:scaleType="fitXY" |             android:scaleType="fitXY" | ||||||
|             android:src="@drawable/exo_controls_previous" |             android:src="@drawable/exo_controls_previous" | ||||||
|             tools:ignore="ContentDescription"/> |             tools:ignore="ContentDescription"/> | ||||||
| @@ -329,7 +334,9 @@ | |||||||
|             android:layout_centerInParent="true" |             android:layout_centerInParent="true" | ||||||
|             android:layout_toRightOf="@id/playPauseButton" |             android:layout_toRightOf="@id/playPauseButton" | ||||||
|             android:layout_toEndOf="@id/playPauseButton" |             android:layout_toEndOf="@id/playPauseButton" | ||||||
|             android:background="#00000000" |             android:clickable="true" | ||||||
|  |             android:focusable="true" | ||||||
|  |             android:background="?attr/selectableItemBackgroundBorderless" | ||||||
|             android:scaleType="fitXY" |             android:scaleType="fitXY" | ||||||
|             android:src="@drawable/exo_controls_next" |             android:src="@drawable/exo_controls_next" | ||||||
|             tools:ignore="ContentDescription"/> |             tools:ignore="ContentDescription"/> | ||||||
|   | |||||||
| @@ -136,6 +136,10 @@ | |||||||
|     <string name="could_not_get_stream">Could not get any stream</string> |     <string name="could_not_get_stream">Could not get any stream</string> | ||||||
|     <string name="could_not_load_image">Could not load image</string> |     <string name="could_not_load_image">Could not load image</string> | ||||||
|     <string name="app_ui_crash">App/UI crashed</string> |     <string name="app_ui_crash">App/UI crashed</string> | ||||||
|  |     <string name="player_video_failure">Failed to play this video</string> | ||||||
|  |     <string name="player_audio_failure">Failed to play this audio</string> | ||||||
|  |     <string name="player_unexpected_failure">Unexpected player error occurred</string> | ||||||
|  |  | ||||||
|     <!-- error activity --> |     <!-- error activity --> | ||||||
|     <string name="sorry_string">Sorry, that should not have happened.</string> |     <string name="sorry_string">Sorry, that should not have happened.</string> | ||||||
|     <string name="guru_meditation" translatable="false">Guru Meditation.</string> |     <string name="guru_meditation" translatable="false">Guru Meditation.</string> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 John Zhen Mo
					John Zhen Mo