Better backstack, better tablet support, switching players confirmation, fix for background playback
This commit is contained in:
parent
d87e488c23
commit
398cbe9284
12 changed files with 140 additions and 51 deletions
|
@ -18,6 +18,7 @@ import android.widget.*;
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.PlaybackParameters;
|
import com.google.android.exoplayer2.PlaybackParameters;
|
||||||
|
@ -74,6 +75,7 @@ import org.schabi.newpipe.views.AnimatedProgressBar;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -86,6 +88,7 @@ import io.reactivex.disposables.Disposable;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
|
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
|
||||||
|
import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
|
||||||
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
|
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
|
||||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
|
||||||
|
@ -237,7 +240,7 @@ public class VideoDetailFragment
|
||||||
|
|
||||||
if (!player.videoPlayerSelected() && !playAfterConnect) return;
|
if (!player.videoPlayerSelected() && !playAfterConnect) return;
|
||||||
|
|
||||||
if (playerIsNotStopped()) addVideoPlayerView();
|
if (playerIsNotStopped() && player.videoPlayerSelected()) addVideoPlayerView();
|
||||||
|
|
||||||
// If the video is playing but orientation changed let's make the video in fullscreen again
|
// If the video is playing but orientation changed let's make the video in fullscreen again
|
||||||
if (isLandscape()) checkLandscape();
|
if (isLandscape()) checkLandscape();
|
||||||
|
@ -382,7 +385,7 @@ public class VideoDetailFragment
|
||||||
|
|
||||||
// Check if it was loading when the fragment was stopped/paused
|
// Check if it was loading when the fragment was stopped/paused
|
||||||
if (wasLoading.getAndSet(false) && !wasCleared())
|
if (wasLoading.getAndSet(false) && !wasCleared())
|
||||||
selectAndLoadVideo(serviceId, url, name, playQueue);
|
startLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -870,16 +873,10 @@ public class VideoDetailFragment
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
StackItem currentPeek = stack.peek();
|
|
||||||
if (currentPeek != null && !currentPeek.getPlayQueue().equals(playQueue)) {
|
|
||||||
// When user selected a stream but didn't start playback this stream will not be added to backStack.
|
|
||||||
// Then he press Back and the last saved item from history will show up
|
|
||||||
setupFromHistoryItem(currentPeek);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have something in history of played items we replay it here
|
// If we have something in history of played items we replay it here
|
||||||
boolean isPreviousCanBePlayed = player != null && player.getPlayQueue() != null && player.videoPlayerSelected()
|
boolean isPreviousCanBePlayed = player != null
|
||||||
|
&& player.getPlayQueue() != null
|
||||||
|
&& player.videoPlayerSelected()
|
||||||
&& player.getPlayQueue().previous();
|
&& player.getPlayQueue().previous();
|
||||||
if (isPreviousCanBePlayed) {
|
if (isPreviousCanBePlayed) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -903,11 +900,15 @@ public class VideoDetailFragment
|
||||||
setAutoplay(false);
|
setAutoplay(false);
|
||||||
hideMainPlayer();
|
hideMainPlayer();
|
||||||
|
|
||||||
selectAndLoadVideo(
|
setInitialData(
|
||||||
item.getServiceId(),
|
item.getServiceId(),
|
||||||
item.getUrl(),
|
item.getUrl(),
|
||||||
!TextUtils.isEmpty(item.getTitle()) ? item.getTitle() : "",
|
!TextUtils.isEmpty(item.getTitle()) ? item.getTitle() : "",
|
||||||
item.getPlayQueue());
|
item.getPlayQueue());
|
||||||
|
startLoading(false);
|
||||||
|
|
||||||
|
// Maybe an item was deleted in background activity
|
||||||
|
if (item.getPlayQueue().getItem() == null) return;
|
||||||
|
|
||||||
PlayQueueItem playQueueItem = item.getPlayQueue().getItem();
|
PlayQueueItem playQueueItem = item.getPlayQueue().getItem();
|
||||||
// Update title, url, uploader from the last item in the stack (it's current now)
|
// Update title, url, uploader from the last item in the stack (it's current now)
|
||||||
|
@ -936,7 +937,7 @@ public class VideoDetailFragment
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setInitialData(serviceId, videoUrl, name, playQueue);
|
setInitialData(serviceId, videoUrl, name, playQueue);
|
||||||
startLoading(false);
|
startLoading(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void prepareAndHandleInfo(final StreamInfo info, boolean scrollToTop) {
|
public void prepareAndHandleInfo(final StreamInfo info, boolean scrollToTop) {
|
||||||
|
@ -965,6 +966,20 @@ public class VideoDetailFragment
|
||||||
currentInfo = null;
|
currentInfo = null;
|
||||||
if (currentWorker != null) currentWorker.dispose();
|
if (currentWorker != null) currentWorker.dispose();
|
||||||
|
|
||||||
|
runWorker(forceLoad, stack.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startLoading(boolean forceLoad, boolean addToBackStack) {
|
||||||
|
super.startLoading(false);
|
||||||
|
|
||||||
|
initTabs();
|
||||||
|
currentInfo = null;
|
||||||
|
if (currentWorker != null) currentWorker.dispose();
|
||||||
|
|
||||||
|
runWorker(forceLoad, addToBackStack);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runWorker(boolean forceLoad, boolean addToBackStack) {
|
||||||
currentWorker = ExtractorHelper.getStreamInfo(serviceId, url, forceLoad)
|
currentWorker = ExtractorHelper.getStreamInfo(serviceId, url, forceLoad)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
@ -973,12 +988,15 @@ public class VideoDetailFragment
|
||||||
hideMainPlayer();
|
hideMainPlayer();
|
||||||
handleResult(result);
|
handleResult(result);
|
||||||
showContent();
|
showContent();
|
||||||
|
if (addToBackStack) {
|
||||||
|
if (playQueue == null) playQueue = new SinglePlayQueue(result);
|
||||||
|
stack.push(new StackItem(serviceId, url, name, playQueue));
|
||||||
|
}
|
||||||
if (isAutoplayEnabled()) openVideoPlayer();
|
if (isAutoplayEnabled()) openVideoPlayer();
|
||||||
}, (@NonNull Throwable throwable) -> {
|
}, (@NonNull Throwable throwable) -> {
|
||||||
isLoading.set(false);
|
isLoading.set(false);
|
||||||
onError(throwable);
|
onError(throwable);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initTabs() {
|
private void initTabs() {
|
||||||
|
@ -1063,7 +1081,9 @@ public class VideoDetailFragment
|
||||||
if (append) {
|
if (append) {
|
||||||
NavigationHelper.enqueueOnPopupPlayer(activity, queue, false);
|
NavigationHelper.enqueueOnPopupPlayer(activity, queue, false);
|
||||||
} else {
|
} else {
|
||||||
NavigationHelper.playOnPopupPlayer(activity, queue, true);
|
Runnable onAllow = () -> NavigationHelper.playOnPopupPlayer(activity, queue, true);
|
||||||
|
if (shouldAskBeforeClearingQueue()) showClearingQueueConfirmation(onAllow);
|
||||||
|
else onAllow.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1073,7 +1093,9 @@ public class VideoDetailFragment
|
||||||
VideoStream selectedVideoStream = getSelectedVideoStream();
|
VideoStream selectedVideoStream = getSelectedVideoStream();
|
||||||
startOnExternalPlayer(activity, currentInfo, selectedVideoStream);
|
startOnExternalPlayer(activity, currentInfo, selectedVideoStream);
|
||||||
} else {
|
} else {
|
||||||
openNormalPlayer();
|
Runnable onAllow = this::openNormalPlayer;
|
||||||
|
if (shouldAskBeforeClearingQueue()) showClearingQueueConfirmation(onAllow);
|
||||||
|
else onAllow.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1085,7 +1107,9 @@ public class VideoDetailFragment
|
||||||
if (append) {
|
if (append) {
|
||||||
NavigationHelper.enqueueOnBackgroundPlayer(activity, queue, false);
|
NavigationHelper.enqueueOnBackgroundPlayer(activity, queue, false);
|
||||||
} else {
|
} else {
|
||||||
NavigationHelper.playOnBackgroundPlayer(activity, queue, true);
|
Runnable onAllow = () -> NavigationHelper.playOnBackgroundPlayer(activity, queue, true);
|
||||||
|
if (shouldAskBeforeClearingQueue()) showClearingQueueConfirmation(onAllow);
|
||||||
|
else onAllow.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1579,7 +1603,7 @@ public class VideoDetailFragment
|
||||||
&& prefs.getBoolean(activity.getString(R.string.enable_playback_resume_key), true);
|
&& prefs.getBoolean(activity.getString(R.string.enable_playback_resume_key), true);
|
||||||
final boolean showPlaybackPosition = prefs.getBoolean(
|
final boolean showPlaybackPosition = prefs.getBoolean(
|
||||||
activity.getString(R.string.enable_playback_state_lists_key), true);
|
activity.getString(R.string.enable_playback_state_lists_key), true);
|
||||||
if (!playbackResumeEnabled || info.getDuration() <= 0) {
|
if (!playbackResumeEnabled) {
|
||||||
if (playQueue == null || playQueue.getStreams().isEmpty()
|
if (playQueue == null || playQueue.getStreams().isEmpty()
|
||||||
|| playQueue.getItem().getRecoveryPosition() == RECOVERY_UNSET || !showPlaybackPosition) {
|
|| playQueue.getItem().getRecoveryPosition() == RECOVERY_UNSET || !showPlaybackPosition) {
|
||||||
positionView.setVisibility(View.INVISIBLE);
|
positionView.setVisibility(View.INVISIBLE);
|
||||||
|
@ -1605,7 +1629,8 @@ public class VideoDetailFragment
|
||||||
}, e -> {
|
}, e -> {
|
||||||
if (DEBUG) e.printStackTrace();
|
if (DEBUG) e.printStackTrace();
|
||||||
}, () -> {
|
}, () -> {
|
||||||
// OnComplete, do nothing
|
animateView(positionView, false, 0);
|
||||||
|
animateView(detailPositionView, false, 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1615,6 +1640,10 @@ public class VideoDetailFragment
|
||||||
positionView.setMax(durationSeconds);
|
positionView.setMax(durationSeconds);
|
||||||
positionView.setProgress(progressSeconds);
|
positionView.setProgress(progressSeconds);
|
||||||
detailPositionView.setText(Localization.getDurationString(progressSeconds));
|
detailPositionView.setText(Localization.getDurationString(progressSeconds));
|
||||||
|
if (positionView.getVisibility() != View.VISIBLE) {
|
||||||
|
animateView(positionView, true, 100);
|
||||||
|
animateView(detailPositionView, true, 100);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1628,11 +1657,11 @@ public class VideoDetailFragment
|
||||||
// information about deleted/added items inside Channel/Playlist queue and makes possible to have a history of played items
|
// information about deleted/added items inside Channel/Playlist queue and makes possible to have a history of played items
|
||||||
if (stack.isEmpty() || !stack.peek().getPlayQueue().equals(queue)) {
|
if (stack.isEmpty() || !stack.peek().getPlayQueue().equals(queue)) {
|
||||||
stack.push(new StackItem(serviceId, url, name, playQueue));
|
stack.push(new StackItem(serviceId, url, name, playQueue));
|
||||||
} else if (stack.peek().getPlayQueue().equals(queue)) {
|
} else if (findQueueInStack(queue) != null) {
|
||||||
// On every MainPlayer service's destroy() playQueue gets disposed and no longer able to track progress.
|
// On every MainPlayer service's destroy() playQueue gets disposed and no longer able to track progress.
|
||||||
// That's why we update our cached disposed queue with the new one that is active and have the same history
|
// That's why we update our cached disposed queue with the new one that is active and have the same history
|
||||||
// Without that the cached playQueue will have an old recovery position
|
// Without that the cached playQueue will have an old recovery position
|
||||||
stack.peek().setPlayQueue(queue);
|
findQueueInStack(queue).setPlayQueue(queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
@ -1671,20 +1700,23 @@ public class VideoDetailFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMetadataUpdate(StreamInfo info) {
|
public void onMetadataUpdate(StreamInfo info, PlayQueue queue) {
|
||||||
if (!stack.isEmpty()) {
|
StackItem item = findQueueInStack(queue);
|
||||||
|
if (item != null) {
|
||||||
// When PlayQueue can have multiple streams (PlaylistPlayQueue or ChannelPlayQueue) every new played stream gives
|
// When PlayQueue can have multiple streams (PlaylistPlayQueue or ChannelPlayQueue) every new played stream gives
|
||||||
// new title and url. StackItem contains information about first played stream. Let's update it here
|
// new title and url. StackItem contains information about first played stream. Let's update it here
|
||||||
StackItem peek = stack.peek();
|
item.setTitle(info.getName());
|
||||||
peek.setTitle(info.getName());
|
item.setUrl(info.getUrl());
|
||||||
peek.setUrl(info.getUrl());
|
|
||||||
}
|
}
|
||||||
|
// They are not equal when user watches something in popup while browsing in fragment and then changes screen orientation
|
||||||
|
// In that case the fragment will set itself as a service listener and will receive initial call to onMetadataUpdate()
|
||||||
|
if (!queue.equals(playQueue)) return;
|
||||||
|
|
||||||
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl());
|
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl());
|
||||||
if (currentInfo != null && info.getUrl().equals(currentInfo.getUrl())) return;
|
if (currentInfo != null && info.getUrl().equals(currentInfo.getUrl())) return;
|
||||||
|
|
||||||
currentInfo = info;
|
currentInfo = info;
|
||||||
setInitialData(info.getServiceId(), info.getUrl(),info.getName(), playQueue);
|
setInitialData(info.getServiceId(), info.getUrl(),info.getName(), queue);
|
||||||
setAutoplay(false);
|
setAutoplay(false);
|
||||||
prepareAndHandleInfo(info, true);
|
prepareAndHandleInfo(info, true);
|
||||||
}
|
}
|
||||||
|
@ -1852,6 +1884,37 @@ public class VideoDetailFragment
|
||||||
return url == null;
|
return url == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private StackItem findQueueInStack(PlayQueue queue) {
|
||||||
|
StackItem item = null;
|
||||||
|
Iterator<StackItem> iterator = stack.descendingIterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
StackItem next = iterator.next();
|
||||||
|
if (next.getPlayQueue().equals(queue)) {
|
||||||
|
item = next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldAskBeforeClearingQueue() {
|
||||||
|
PlayQueue activeQueue = player != null ? player.getPlayQueue() : null;
|
||||||
|
// Player will have STATE_IDLE when a user pressed back button
|
||||||
|
return isClearingQueueConfirmationRequired(activity) && playerIsNotStopped()
|
||||||
|
&& activeQueue != null && !activeQueue.equals(playQueue) && activeQueue.getStreams().size() > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showClearingQueueConfirmation(Runnable onAllow) {
|
||||||
|
new AlertDialog.Builder(activity)
|
||||||
|
.setTitle(R.string.confirm_prompt)
|
||||||
|
.setMessage(R.string.clear_queue_confirmation_description)
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
|
||||||
|
onAllow.run();
|
||||||
|
dialog.dismiss();
|
||||||
|
}).show();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove unneeded information while waiting for a next task
|
* Remove unneeded information while waiting for a next task
|
||||||
* */
|
* */
|
||||||
|
@ -1905,6 +1968,7 @@ public class VideoDetailFragment
|
||||||
&& player != null
|
&& player != null
|
||||||
&& player.isPlaying()
|
&& player.isPlaying()
|
||||||
&& !player.isInFullscreen()
|
&& !player.isInFullscreen()
|
||||||
|
&& !PlayerHelper.isTablet(activity)
|
||||||
&& player.videoPlayerSelected();
|
&& player.videoPlayerSelected();
|
||||||
if (needToExpand) player.toggleFullscreen();
|
if (needToExpand) player.toggleFullscreen();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -451,7 +451,7 @@ public final class BackgroundPlayer extends Service {
|
||||||
|
|
||||||
private void updateMetadata() {
|
private void updateMetadata() {
|
||||||
if (activityListener != null && getCurrentMetadata() != null) {
|
if (activityListener != null && getCurrentMetadata() != null) {
|
||||||
activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata());
|
activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata(), playQueue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1236,6 +1236,10 @@ public abstract class BasePlayer implements
|
||||||
return simpleExoPlayer != null && simpleExoPlayer.isPlaying();
|
return simpleExoPlayer != null && simpleExoPlayer.isPlaying();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLoading() {
|
||||||
|
return simpleExoPlayer != null && simpleExoPlayer.isLoading();
|
||||||
|
}
|
||||||
|
|
||||||
@Player.RepeatMode
|
@Player.RepeatMode
|
||||||
public int getRepeatMode() {
|
public int getRepeatMode() {
|
||||||
return simpleExoPlayer == null
|
return simpleExoPlayer == null
|
||||||
|
|
|
@ -673,7 +673,7 @@ public final class PopupVideoPlayer extends Service {
|
||||||
|
|
||||||
private void updateMetadata() {
|
private void updateMetadata() {
|
||||||
if (activityListener != null && getCurrentMetadata() != null) {
|
if (activityListener != null && getCurrentMetadata() != null) {
|
||||||
activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata());
|
activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata(), playQueue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -596,7 +596,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMetadataUpdate(StreamInfo info) {
|
public void onMetadataUpdate(StreamInfo info, PlayQueue queue) {
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
metadataTitle.setText(info.getName());
|
metadataTitle.setText(info.getName());
|
||||||
metadataArtist.setText(info.getUploaderName());
|
metadataArtist.setText(info.getUploaderName());
|
||||||
|
|
|
@ -761,7 +761,8 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
|
|
||||||
private void setupScreenRotationButton() {
|
private void setupScreenRotationButton() {
|
||||||
boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
|
boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
|
||||||
boolean showButton = (orientationLocked || isVerticalVideo || isTablet(service)) && videoPlayerSelected();
|
boolean tabletInLandscape = isTablet(service) && service.isLandscape();
|
||||||
|
boolean showButton = videoPlayerSelected() && (orientationLocked || isVerticalVideo || tabletInLandscape);
|
||||||
screenRotationButton.setVisibility(showButton ? View.VISIBLE : View.GONE);
|
screenRotationButton.setVisibility(showButton ? View.VISIBLE : View.GONE);
|
||||||
screenRotationButton.setImageDrawable(service.getResources().getDrawable(
|
screenRotationButton.setImageDrawable(service.getResources().getDrawable(
|
||||||
isInFullscreen() ? R.drawable.ic_fullscreen_exit_white : R.drawable.ic_fullscreen_white));
|
isInFullscreen() ? R.drawable.ic_fullscreen_exit_white : R.drawable.ic_fullscreen_white));
|
||||||
|
@ -1048,10 +1049,10 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
useVideoSource(true);
|
useVideoSource(true);
|
||||||
break;
|
break;
|
||||||
case VideoDetailFragment.ACTION_VIDEO_FRAGMENT_STOPPED:
|
case VideoDetailFragment.ACTION_VIDEO_FRAGMENT_STOPPED:
|
||||||
// This will be called when user goes to another app
|
// This will be called when user goes to another app/activity, turns off a screen.
|
||||||
// We don't want to interrupt playback and don't want to see notification if player is stopped
|
// We don't want to interrupt playback and don't want to see notification if player is stopped.
|
||||||
// since next lines of code will enable background playback if needed
|
// Next lines of code will enable background playback if needed
|
||||||
if (videoPlayerSelected() && isPlaying()) {
|
if (videoPlayerSelected() && (isPlaying() || isLoading())) {
|
||||||
if (backgroundPlaybackEnabled()) {
|
if (backgroundPlaybackEnabled()) {
|
||||||
useVideoSource(false);
|
useVideoSource(false);
|
||||||
} else if (minimizeOnPopupEnabled()) {
|
} else if (minimizeOnPopupEnabled()) {
|
||||||
|
@ -1076,14 +1077,15 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
break;
|
break;
|
||||||
case Intent.ACTION_SCREEN_ON:
|
case Intent.ACTION_SCREEN_ON:
|
||||||
shouldUpdateOnProgress = true;
|
shouldUpdateOnProgress = true;
|
||||||
// Interrupt playback only when screen turns on and user is watching video in fragment
|
// Interrupt playback only when screen turns on and user is watching video in popup player
|
||||||
if (backgroundPlaybackEnabled() && getPlayer() != null && (isPlaying() || getPlayer().isLoading()))
|
// Same action for video player will be handled in ACTION_VIDEO_FRAGMENT_RESUMED event
|
||||||
|
if (backgroundPlaybackEnabled() && popupPlayerSelected() && (isPlaying() || isLoading()))
|
||||||
useVideoSource(true);
|
useVideoSource(true);
|
||||||
break;
|
break;
|
||||||
case Intent.ACTION_SCREEN_OFF:
|
case Intent.ACTION_SCREEN_OFF:
|
||||||
shouldUpdateOnProgress = false;
|
shouldUpdateOnProgress = false;
|
||||||
// Interrupt playback only when screen turns off with video working
|
// Interrupt playback only when screen turns off with popup player working
|
||||||
if (backgroundPlaybackEnabled() && getPlayer() != null && (isPlaying() || getPlayer().isLoading()))
|
if (backgroundPlaybackEnabled() && popupPlayerSelected() && (isPlaying() || isLoading()))
|
||||||
useVideoSource(false);
|
useVideoSource(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1330,7 +1332,7 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
AppCompatActivity parent = getParentActivity();
|
AppCompatActivity parent = getParentActivity();
|
||||||
boolean videoInLandscapeButNotInFullscreen = service.isLandscape() && !isInFullscreen() && videoPlayerSelected() && !audioOnly;
|
boolean videoInLandscapeButNotInFullscreen = service.isLandscape() && !isInFullscreen() && videoPlayerSelected() && !audioOnly;
|
||||||
boolean playingState = getCurrentState() != STATE_COMPLETED && getCurrentState() != STATE_PAUSED;
|
boolean playingState = getCurrentState() != STATE_COMPLETED && getCurrentState() != STATE_PAUSED;
|
||||||
if (parent != null && videoInLandscapeButNotInFullscreen && playingState)
|
if (parent != null && videoInLandscapeButNotInFullscreen && playingState && !PlayerHelper.isTablet(service))
|
||||||
toggleFullscreen();
|
toggleFullscreen();
|
||||||
|
|
||||||
setControlsSize();
|
setControlsSize();
|
||||||
|
@ -1695,10 +1697,10 @@ public class VideoPlayerImpl extends VideoPlayer
|
||||||
|
|
||||||
private void updateMetadata() {
|
private void updateMetadata() {
|
||||||
if (fragmentListener != null && getCurrentMetadata() != null) {
|
if (fragmentListener != null && getCurrentMetadata() != null) {
|
||||||
fragmentListener.onMetadataUpdate(getCurrentMetadata().getMetadata());
|
fragmentListener.onMetadataUpdate(getCurrentMetadata().getMetadata(), playQueue);
|
||||||
}
|
}
|
||||||
if (activityListener != null && getCurrentMetadata() != null) {
|
if (activityListener != null && getCurrentMetadata() != null) {
|
||||||
activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata());
|
activityListener.onMetadataUpdate(getCurrentMetadata().getMetadata(), playQueue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ public class CustomBottomSheetBehavior extends BottomSheetBehavior<FrameLayout>
|
||||||
// Found that user still swiping, continue following
|
// Found that user still swiping, continue following
|
||||||
if (skippingInterception) return false;
|
if (skippingInterception) return false;
|
||||||
|
|
||||||
|
// Don't need to do anything if bottomSheet isn't expanded
|
||||||
|
if (getState() == BottomSheetBehavior.STATE_EXPANDED) {
|
||||||
// Without overriding scrolling will not work when user touches these elements
|
// Without overriding scrolling will not work when user touches these elements
|
||||||
for (Integer element : skipInterceptionOfElements) {
|
for (Integer element : skipInterceptionOfElements) {
|
||||||
ViewGroup viewGroup = child.findViewById(element);
|
ViewGroup viewGroup = child.findViewById(element);
|
||||||
|
@ -46,6 +48,7 @@ public class CustomBottomSheetBehavior extends BottomSheetBehavior<FrameLayout>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return super.onInterceptTouchEvent(parent, child, event);
|
return super.onInterceptTouchEvent(parent, child, event);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,6 @@ public interface PlayerEventListener {
|
||||||
void onQueueUpdate(PlayQueue queue);
|
void onQueueUpdate(PlayQueue queue);
|
||||||
void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, PlaybackParameters parameters);
|
void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, PlaybackParameters parameters);
|
||||||
void onProgressUpdate(int currentProgress, int duration, int bufferPercent);
|
void onProgressUpdate(int currentProgress, int duration, int bufferPercent);
|
||||||
void onMetadataUpdate(StreamInfo info);
|
void onMetadataUpdate(StreamInfo info, PlayQueue queue);
|
||||||
void onServiceStopped();
|
void onServiceStopped();
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,6 +200,10 @@ public class PlayerHelper {
|
||||||
return isAutoQueueEnabled(context, false);
|
return isAutoQueueEnabled(context, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isClearingQueueConfirmationRequired(@NonNull final Context context) {
|
||||||
|
return getPreferences(context).getBoolean(context.getString(R.string.clear_queue_confirmation_key), false);
|
||||||
|
}
|
||||||
|
|
||||||
@MinimizeMode
|
@MinimizeMode
|
||||||
public static int getMinimizeOnExitAction(@NonNull final Context context) {
|
public static int getMinimizeOnExitAction(@NonNull final Context context) {
|
||||||
final String defaultAction = context.getString(R.string.minimize_on_exit_none_key);
|
final String defaultAction = context.getString(R.string.minimize_on_exit_none_key);
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
<string name="auto_queue_key" translatable="false">auto_queue_key</string>
|
<string name="auto_queue_key" translatable="false">auto_queue_key</string>
|
||||||
<string name="screen_brightness_key" translatable="false">screen_brightness_key</string>
|
<string name="screen_brightness_key" translatable="false">screen_brightness_key</string>
|
||||||
<string name="screen_brightness_timestamp_key" translatable="false">screen_brightness_timestamp_key</string>
|
<string name="screen_brightness_timestamp_key" translatable="false">screen_brightness_timestamp_key</string>
|
||||||
|
<string name="clear_queue_confirmation_key" translatable="false">clear_queue_confirmation_key</string>
|
||||||
|
|
||||||
<string name="seek_duration_key" translatable="false">seek_duration</string>
|
<string name="seek_duration_key" translatable="false">seek_duration</string>
|
||||||
<string name="seek_duration_default_value" translatable="false">10000</string>
|
<string name="seek_duration_default_value" translatable="false">10000</string>
|
||||||
|
|
|
@ -71,6 +71,9 @@
|
||||||
<string name="use_inexact_seek_title">Use fast inexact seek</string>
|
<string name="use_inexact_seek_title">Use fast inexact seek</string>
|
||||||
<string name="use_inexact_seek_summary">Inexact seek allows the player to seek to positions faster with reduced precision</string>
|
<string name="use_inexact_seek_summary">Inexact seek allows the player to seek to positions faster with reduced precision</string>
|
||||||
<string name="seek_duration_title">Fast-forward/-rewind seek duration</string>
|
<string name="seek_duration_title">Fast-forward/-rewind seek duration</string>
|
||||||
|
<string name="clear_queue_confirmation_title">Ask confirmation before clearing a queue</string>
|
||||||
|
<string name="clear_queue_confirmation_summary">After switching from one player to another your queue may be replaced</string>
|
||||||
|
<string name="clear_queue_confirmation_description">Queue from the active player will be replaced</string>
|
||||||
<string name="download_thumbnail_title">Load thumbnails</string>
|
<string name="download_thumbnail_title">Load thumbnails</string>
|
||||||
<string name="show_comments_title">Show comments</string>
|
<string name="show_comments_title">Show comments</string>
|
||||||
<string name="show_comments_summary">Disable to stop showing comments</string>
|
<string name="show_comments_summary">Disable to stop showing comments</string>
|
||||||
|
|
|
@ -164,5 +164,13 @@
|
||||||
android:key="@string/seek_duration_key"
|
android:key="@string/seek_duration_key"
|
||||||
android:summary="%s"
|
android:summary="%s"
|
||||||
android:title="@string/seek_duration_title"/>
|
android:title="@string/seek_duration_title"/>
|
||||||
|
|
||||||
|
<SwitchPreference
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="@string/clear_queue_confirmation_key"
|
||||||
|
android:summary="@string/clear_queue_confirmation_summary"
|
||||||
|
android:title="@string/clear_queue_confirmation_title"/>
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
Loading…
Reference in a new issue