-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:
parent
d0e626c6ee
commit
0806344ffb
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue