From 6d7e37610c80ee3a4a6918c595499e4f0d54054d Mon Sep 17 00:00:00 2001
From: Avently <7953703+avently@users.noreply.github.com>
Date: Tue, 25 Feb 2020 02:15:22 +0300
Subject: [PATCH] Vertical videos in portrait & fullscreen, UI enhancements for
tablets and phones, fixes - vertical videos now work ok in portrait and
fullscreen mode at the same time - auto pause on back press is disabled for
large tablets - large dragable area for swipe to bottom in fullscreen mode in
place of top controls - appbar will be scrolled to top when entering in
fullscreen mode
---
.../fragments/detail/VideoDetailFragment.java | 11 +--
.../newpipe/player/VideoPlayerImpl.java | 75 ++++++++++++++-----
.../player/event/PlayerGestureListener.java | 5 +-
.../activity_main_player.xml | 44 +++++------
.../main/res/layout/activity_main_player.xml | 44 +++++------
5 files changed, 112 insertions(+), 67 deletions(-)
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index 6f65c34dc..a946e3f99 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -870,7 +870,7 @@ public class VideoDetailFragment
// If we are in fullscreen mode just exit from it via first back press
if (player != null && player.isInFullscreen()) {
- player.onPause();
+ if (!PlayerHelper.isTablet(activity)) player.onPause();
restoreDefaultOrientation();
setAutoplay(false);
return true;
@@ -1699,6 +1699,7 @@ public class VideoDetailFragment
if (currentInfo != null && info.getUrl().equals(currentInfo.getUrl())) return;
currentInfo = info;
+ setInitialData(info.getServiceId(), info.getUrl(),info.getName(), playQueue);
setAutoplay(false);
prepareAndHandleInfo(info, true);
}
@@ -1736,6 +1737,7 @@ public class VideoDetailFragment
}
if (relatedStreamsLayout != null) relatedStreamsLayout.setVisibility(fullscreen ? View.GONE : View.VISIBLE);
+ scrollToTop();
addVideoPlayerView();
}
@@ -1842,12 +1844,10 @@ public class VideoDetailFragment
if ((!player.isPlaying() && player.getPlayQueue() != playQueue) || player.getPlayQueue() == null)
setAutoplay(true);
+ player.checkLandscape();
boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(activity);
// Let's give a user time to look at video information page if video is not playing
- if (player.isPlaying()) {
- player.checkLandscape();
- } else if (orientationLocked) {
- player.checkLandscape();
+ if (orientationLocked && !player.isPlaying()) {
player.onPlay();
player.showControlsThenHide();
}
@@ -1927,6 +1927,7 @@ public class VideoDetailFragment
case BottomSheetBehavior.STATE_COLLAPSED:
// Re-enable clicks
setOverlayElementsClickable(true);
+ if (player != null) player.onQueueClosed();
break;
case BottomSheetBehavior.STATE_DRAGGING:
case BottomSheetBehavior.STATE_SETTLING:
diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
index 78f6aa387..ec490451b 100644
--- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
+++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
@@ -74,9 +74,11 @@ import org.schabi.newpipe.util.*;
import java.util.List;
import static android.content.Context.WINDOW_SERVICE;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static org.schabi.newpipe.player.MainPlayer.*;
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_BACKGROUND;
import static org.schabi.newpipe.player.helper.PlayerHelper.getTimeString;
+import static org.schabi.newpipe.player.helper.PlayerHelper.isTablet;
import static org.schabi.newpipe.util.AnimationUtils.Type.SLIDE_AND_ALPHA;
import static org.schabi.newpipe.util.AnimationUtils.animateRotation;
import static org.schabi.newpipe.util.AnimationUtils.animateView;
@@ -137,6 +139,7 @@ public class VideoPlayerImpl extends VideoPlayer
private boolean audioOnly = false;
private boolean isFullscreen = false;
+ private boolean isVerticalVideo = false;
boolean shouldUpdateOnProgress;
private MainPlayer service;
@@ -305,11 +308,13 @@ public class VideoPlayerImpl extends VideoPlayer
openInBrowser.setVisibility(View.GONE);
playerCloseButton.setVisibility(View.GONE);
getTopControlsRoot().bringToFront();
+ getTopControlsRoot().setClickable(false);
+ getTopControlsRoot().setFocusable(false);
getBottomControlsRoot().bringToFront();
onQueueClosed();
} else {
fullscreenButton.setVisibility(View.GONE);
- setupScreenRotationButton(service.isLandscape());
+ setupScreenRotationButton();
getResizeView().setVisibility(View.VISIBLE);
getRootView().findViewById(R.id.metadataView).setVisibility(View.VISIBLE);
moreOptionsButton.setVisibility(View.VISIBLE);
@@ -323,6 +328,10 @@ public class VideoPlayerImpl extends VideoPlayer
defaultPreferences.getBoolean(service.getString(R.string.show_play_with_kodi_key), false) ? View.VISIBLE : View.GONE);
openInBrowser.setVisibility(View.VISIBLE);
playerCloseButton.setVisibility(isFullscreen ? View.GONE : View.VISIBLE);
+ // Top controls have a large minHeight which is allows to drag the player down in fullscreen mode (just larger area
+ // to make easy to locate by finger)
+ getTopControlsRoot().setClickable(true);
+ getTopControlsRoot().setFocusable(true);
}
if (!isInFullscreen()) {
titleTextView.setVisibility(View.GONE);
@@ -393,7 +402,7 @@ public class VideoPlayerImpl extends VideoPlayer
settingsContentObserver = new ContentObserver(new Handler()) {
@Override
- public void onChange(boolean selfChange) { setupScreenRotationButton(service.isLandscape()); }
+ public void onChange(boolean selfChange) { setupScreenRotationButton(); }
};
service.getContentResolver().registerContentObserver(
Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), false,
@@ -442,6 +451,14 @@ public class VideoPlayerImpl extends VideoPlayer
setPlaybackParameters(playbackTempo, playbackPitch, playbackSkipSilence);
}
+ @Override
+ public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
+ super.onVideoSizeChanged(width, height, unappliedRotationDegrees, pixelWidthHeightRatio);
+ isVerticalVideo = width < height;
+ prepareOrientation();
+ setupScreenRotationButton();
+ }
+
/*//////////////////////////////////////////////////////////////////////////
// ExoPlayer Video Listener
//////////////////////////////////////////////////////////////////////////*/
@@ -597,7 +614,7 @@ public class VideoPlayerImpl extends VideoPlayer
channelTextView.setVisibility(View.VISIBLE);
playerCloseButton.setVisibility(View.GONE);
}
- setupScreenRotationButton(isInFullscreen());
+ setupScreenRotationButton();
}
@Override
@@ -637,7 +654,8 @@ public class VideoPlayerImpl extends VideoPlayer
toggleFullscreen();
} else if (v.getId() == screenRotationButton.getId()) {
- fragmentListener.onScreenRotationButtonClicked();
+ if (!isVerticalVideo) fragmentListener.onScreenRotationButtonClicked();
+ else toggleFullscreen();
} else if (v.getId() == playerCloseButton.getId()) {
service.sendBroadcast(new Intent(VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER));
@@ -667,6 +685,7 @@ public class VideoPlayerImpl extends VideoPlayer
private void onQueueClicked() {
queueVisible = true;
+ hideSystemUIIfNeeded();
buildQueue();
updatePlaybackButtons();
@@ -677,7 +696,9 @@ public class VideoPlayerImpl extends VideoPlayer
itemsList.scrollToPosition(playQueue.getIndex());
}
- private void onQueueClosed() {
+ public void onQueueClosed() {
+ if (!queueVisible) return;
+
animateView(queueLayout, SLIDE_AND_ALPHA, /*visible=*/false,
DEFAULT_CONTROLS_DURATION, 0, () -> {
// Even when queueLayout is GONE it receives touch events and ruins normal behavior of the app. This line fixes it
@@ -733,11 +754,18 @@ public class VideoPlayerImpl extends VideoPlayer
builder.create().show();
}
- private void setupScreenRotationButton(boolean landscape) {
+ private void setupScreenRotationButton() {
boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
- screenRotationButton.setVisibility(orientationLocked && videoPlayerSelected() ? View.VISIBLE : View.GONE);
+ boolean showButton = (orientationLocked || isVerticalVideo || isTablet(service)) && videoPlayerSelected();
+ screenRotationButton.setVisibility(showButton ? View.VISIBLE : View.GONE);
screenRotationButton.setImageDrawable(service.getResources().getDrawable(
- landscape ? R.drawable.ic_fullscreen_exit_white : R.drawable.ic_fullscreen_white));
+ isInFullscreen() ? R.drawable.ic_fullscreen_exit_white : R.drawable.ic_fullscreen_white));
+ }
+
+ private void prepareOrientation() {
+ boolean orientationLocked = PlayerHelper.globalScreenOrientationLocked(service);
+ if (orientationLocked && isInFullscreen() && service.isLandscape() == isVerticalVideo && fragmentListener != null)
+ fragmentListener.onScreenRotationButtonClicked();
}
@Override
@@ -779,7 +807,7 @@ public class VideoPlayerImpl extends VideoPlayer
brightnessProgressBar.setMax(maxGestureLength);
setInitialGestureValues();
- queueLayout.getLayoutParams().height = min - queueLayout.getTop();
+ queueLayout.getLayoutParams().height = height - queueLayout.getTop();
if (popupPlayerSelected()) {
float widthDp = Math.abs(r - l) / service.getResources().getDisplayMetrics().density;
@@ -1009,7 +1037,16 @@ public class VideoPlayerImpl extends VideoPlayer
onRepeatClicked();
break;
case Intent.ACTION_CONFIGURATION_CHANGED:
- setControlsSize();
+ // The only situation I need to re-calculate elements sizes is when a user rotates a device from landscape to landscape
+ // because in that case the controls should be aligned to another side of a screen. The problem is when user leaves
+ // the app and returns back (while the app in landscape) Android reports via DisplayMetrics that orientation is
+ // portrait and it gives wrong sizes calculations. Let's skip re-calculation in every case but landscape
+ boolean reportedOrientationIsLandscape = service.isLandscape();
+ boolean actualOrientationIsLandscape = context.getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE;
+ if (reportedOrientationIsLandscape && actualOrientationIsLandscape) setControlsSize();
+ // Close it because when changing orientation from portrait (in fullscreen mode) the size of queue layout can be
+ // larger than the screen size
+ onQueueClosed();
break;
case Intent.ACTION_SCREEN_ON:
shouldUpdateOnProgress = true;
@@ -1201,7 +1238,7 @@ public class VideoPlayerImpl extends VideoPlayer
// It doesn't include NavigationBar, notches, etc.
display.getSize(size);
- int width = isFullscreen ? size.x : ViewGroup.LayoutParams.MATCH_PARENT;
+ int width = isFullscreen ? (service.isLandscape() ? size.x : size.y) : ViewGroup.LayoutParams.MATCH_PARENT;
int gravity = isFullscreen ? (display.getRotation() == Surface.ROTATION_90 ? Gravity.START : Gravity.END) : Gravity.TOP;
getTopControlsRoot().getLayoutParams().width = width;
@@ -1218,10 +1255,11 @@ public class VideoPlayerImpl extends VideoPlayer
bottomParams.addRule(gravity == Gravity.END ? RelativeLayout.ALIGN_PARENT_END : RelativeLayout.ALIGN_PARENT_START);
getBottomControlsRoot().requestLayout();
- ViewGroup controlsRoot = getRootView().findViewById(R.id.playbackControlRoot);
- // In tablet navigationBar located at the bottom of the screen. And the only situation when we need to set custom height is
- // in fullscreen mode in tablet in non-multiWindow mode. Other than that MATCH_PARENT is good
- controlsRoot.getLayoutParams().height = isFullscreen && !isInMultiWindow() && PlayerHelper.isTablet(service)
+ ViewGroup controlsRoot = getRootView().findViewById(R.id.playbackWindowRoot);
+ // In tablet navigationBar located at the bottom of the screen. And the situations when we need to set custom height is
+ // in fullscreen mode in tablet in non-multiWindow mode or with vertical video. Other than that MATCH_PARENT is good
+ boolean navBarAtTheBottom = PlayerHelper.isTablet(service) || !service.isLandscape();
+ controlsRoot.getLayoutParams().height = isFullscreen && !isInMultiWindow() && navBarAtTheBottom
? size.y
: ViewGroup.LayoutParams.MATCH_PARENT;
controlsRoot.requestLayout();
@@ -1264,9 +1302,12 @@ public class VideoPlayerImpl extends VideoPlayer
public void checkLandscape() {
AppCompatActivity parent = getParentActivity();
- if (parent != null && service.isLandscape() != isInFullscreen()
- && getCurrentState() != STATE_COMPLETED && videoPlayerSelected() && !audioOnly)
+ boolean videoInLandscapeButNotInFullscreen = service.isLandscape() && !isInFullscreen() && videoPlayerSelected() && !audioOnly;
+ boolean playingState = getCurrentState() != STATE_COMPLETED && getCurrentState() != STATE_PAUSED;
+ if (parent != null && videoInLandscapeButNotInFullscreen && playingState)
toggleFullscreen();
+
+ setControlsSize();
}
private void buildQueue() {
diff --git a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
index db7d8d615..bb9ede4d7 100644
--- a/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
+++ b/app/src/main/java/org/schabi/newpipe/player/event/PlayerGestureListener.java
@@ -160,9 +160,8 @@ public class PlayerGestureListener extends GestureDetector.SimpleOnGestureListen
isMovingInMain = true;
- boolean acceptAnyArea = isVolumeGestureEnabled != isBrightnessGestureEnabled;
- boolean acceptVolumeArea = acceptAnyArea || initialEvent.getX() > playerImpl.getRootView().getWidth() / 2;
- boolean acceptBrightnessArea = acceptAnyArea || !acceptVolumeArea;
+ boolean acceptVolumeArea = initialEvent.getX() > playerImpl.getRootView().getWidth() / 2.0;
+ boolean acceptBrightnessArea = initialEvent.getX() <= playerImpl.getRootView().getWidth() / 2.0;
if (isVolumeGestureEnabled && acceptVolumeArea) {
playerImpl.getVolumeProgressBar().incrementProgressBy((int) distanceY);
diff --git a/app/src/main/res/layout-large-land/activity_main_player.xml b/app/src/main/res/layout-large-land/activity_main_player.xml
index 4a4879d7f..d87930371 100644
--- a/app/src/main/res/layout-large-land/activity_main_player.xml
+++ b/app/src/main/res/layout-large-land/activity_main_player.xml
@@ -12,7 +12,7 @@
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_centerHorizontal="true"/>
+ android:layout_centerInParent="true"/>
+
+
-
-
-
+
+ android:layout_centerInParent="true"/>
+
+
-
-
-
+