From 3c2ea7697c596002c1fec7fe97e615bccb7db585 Mon Sep 17 00:00:00 2001 From: Stypox Date: Tue, 19 Jan 2021 08:13:44 +0100 Subject: [PATCH 1/8] Add option to directly open fullscreen when the main player starts --- .../fragments/detail/VideoDetailFragment.java | 25 +++++++++++++------ .../org/schabi/newpipe/player/Player.java | 4 +-- .../newpipe/player/helper/PlayerHelper.java | 5 ++++ .../schabi/newpipe/util/NavigationHelper.java | 10 +++++++- app/src/main/res/values/settings_keys.xml | 2 ++ app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/xml/video_audio_settings.xml | 8 ++++++ 7 files changed, 44 insertions(+), 12 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 0b3ddc3c3..a39ef0a0a 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 @@ -241,7 +241,7 @@ public final class VideoDetailFragment && isAutoplayEnabled() && player.getParentActivity() == null)) { autoPlayEnabled = true; // forcefully start playing - openVideoPlayer(); + openVideoPlayer(true); } } @@ -499,7 +499,7 @@ public final class VideoDetailFragment break; case R.id.detail_thumbnail_root_layout: autoPlayEnabled = true; // forcefully start playing - openVideoPlayer(); + openVideoPlayer(true); break; case R.id.detail_title_root_layout: toggleTitleAndSecondaryControls(); @@ -516,7 +516,7 @@ public final class VideoDetailFragment showSystemUi(); } else { autoPlayEnabled = true; // forcefully start playing - openVideoPlayer(); + openVideoPlayer(false); } setOverlayPlayPauseImage(isPlayerAvailable() && player.isPlaying()); @@ -897,8 +897,9 @@ public final class VideoDetailFragment stack.push(new StackItem(serviceId, url, title, playQueue)); } } + if (isAutoplayEnabled()) { - openVideoPlayer(); + openVideoPlayer(true); } } }, throwable -> showError(new ErrorInfo(throwable, UserAction.REQUESTED_STREAM, @@ -1103,7 +1104,15 @@ public final class VideoDetailFragment } } - public void openVideoPlayer() { + public void openVideoPlayer(final boolean directlyFullscreenIfApplicable) { + if (directlyFullscreenIfApplicable + && PlayerHelper.isStartMainPlayerFullscreenEnabled(requireContext()) + && !isLandscape() + && PlayerHelper.globalScreenOrientationLocked(requireContext())) { + // open directly in fullscreen TODO does it work for large-land layouts? + onScreenRotationButtonClicked(); + } + if (PreferenceManager.getDefaultSharedPreferences(activity) .getBoolean(this.getString(R.string.use_external_video_player_key), false)) { showExternalPlaybackDialog(); @@ -1145,8 +1154,8 @@ public final class VideoDetailFragment } addVideoPlayerView(); - final Intent playerIntent = NavigationHelper - .getPlayerIntent(requireContext(), MainPlayer.class, queue, true, autoPlayEnabled); + final Intent playerIntent = NavigationHelper.getPlayerIntent(requireContext(), + MainPlayer.class, queue, true, autoPlayEnabled); ContextCompat.startForegroundService(activity, playerIntent); } @@ -2022,7 +2031,7 @@ public final class VideoDetailFragment } } - private boolean isLandscape() { + public boolean isLandscape() { return getResources().getDisplayMetrics().heightPixels < getResources() .getDisplayMetrics().widthPixels; } diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java index ae9720474..10532c5eb 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -3855,11 +3855,9 @@ public final class Player implements if (DEBUG) { Log.d(TAG, "toggleFullscreen() called"); } - if (popupPlayerSelected() || exoPlayerIsNull() || currentMetadata == null - || fragmentListener == null) { + if (popupPlayerSelected() || exoPlayerIsNull() || fragmentListener == null) { return; } - //changeState(STATE_BLOCKED); TODO check what this does isFullscreen = !isFullscreen; if (!isFullscreen) { diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java index b19e6e823..828833a8d 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java @@ -239,6 +239,11 @@ public final class PlayerHelper { .getBoolean(context.getString(R.string.brightness_gesture_control_key), true); } + public static boolean isStartMainPlayerFullscreenEnabled(@NonNull final Context context) { + return getPreferences(context) + .getBoolean(context.getString(R.string.start_main_player_fullscreen_key), false); + } + public static boolean isAutoQueueEnabled(@NonNull final Context context) { return getPreferences(context) .getBoolean(context.getString(R.string.auto_queue_key), false); diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java index ad9654073..539387082 100644 --- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java @@ -366,7 +366,15 @@ public final class NavigationHelper { if (switchingPlayers) { // Situation when user switches from players to main player. All needed data is // here, we can start watching (assuming newQueue equals playQueue). - detailFragment.openVideoPlayer(); + + // Starting directly in fullscreen if the previous player type was popup. + if (playerType == MainPlayer.PlayerType.POPUP + && !detailFragment.isLandscape() + && PlayerHelper.globalScreenOrientationLocked(context)) { + detailFragment.onScreenRotationButtonClicked(); + } + // pass false to directlyFullscreenIfApplicable since that's handled just above here + detailFragment.openVideoPlayer(false); } else { detailFragment.selectAndLoadVideo(serviceId, url, title, playQueue); } diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 45400d667..013b970c1 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -73,6 +73,8 @@ @string/minimize_on_exit_popup_description + start_main_player_fullscreen_key + autoplay_key @string/autoplay_wifi_key autoplay_always_key diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 91e9db335..f833dc716 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -132,6 +132,8 @@ Resume playing Continue playing after interruptions (e.g. phonecalls) Download + Start main player in fullscreen + Do not start videos in the mini player, but turn to fullscreen mode directly, if auto rotation is locked. You can still access the mini player by exiting fullscreen. Autoplay Show \"Hold to append\" tip Show tip when pressing the background or the popup button in video \"Details:\" diff --git a/app/src/main/res/xml/video_audio_settings.xml b/app/src/main/res/xml/video_audio_settings.xml index 1b595be0c..f605fbe17 100644 --- a/app/src/main/res/xml/video_audio_settings.xml +++ b/app/src/main/res/xml/video_audio_settings.xml @@ -129,6 +129,14 @@ app:singleLineTitle="false" app:iconSpaceReserved="false" /> + + Date: Thu, 25 Mar 2021 22:54:55 +0100 Subject: [PATCH 2/8] Extract isLandscape and isInMultiWindow to DeviceUtils --- .../fragments/detail/VideoDetailFragment.java | 30 ++++++++----------- .../org/schabi/newpipe/player/MainPlayer.java | 9 ++---- .../org/schabi/newpipe/util/DeviceUtils.java | 10 +++++++ .../schabi/newpipe/util/NavigationHelper.java | 2 +- 4 files changed, 26 insertions(+), 25 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 a39ef0a0a..950430463 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 @@ -220,7 +220,7 @@ public final class VideoDetailFragment return; } - if (isLandscape()) { + if (DeviceUtils.isLandscape(requireContext())) { // If the video is playing but orientation changed // let's make the video in fullscreen again checkLandscape(); @@ -1107,7 +1107,7 @@ public final class VideoDetailFragment public void openVideoPlayer(final boolean directlyFullscreenIfApplicable) { if (directlyFullscreenIfApplicable && PlayerHelper.isStartMainPlayerFullscreenEnabled(requireContext()) - && !isLandscape() + && !DeviceUtils.isLandscape(requireContext()) && PlayerHelper.globalScreenOrientationLocked(requireContext())) { // open directly in fullscreen TODO does it work for large-land layouts? onScreenRotationButtonClicked(); @@ -1261,7 +1261,7 @@ public final class VideoDetailFragment final DisplayMetrics metrics = getResources().getDisplayMetrics(); if (getView() != null) { - final int height = (isInMultiWindow() + final int height = (DeviceUtils.isInMultiWindow(activity) ? requireView() : activity.getWindow().getDecorView()).getHeight(); setHeightThumbnail(height, metrics); @@ -1284,7 +1284,7 @@ public final class VideoDetailFragment requireView().getViewTreeObserver().removeOnPreDrawListener(preDrawListener); if (isPlayerAvailable() && player.isFullscreen()) { - final int height = (isInMultiWindow() + final int height = (DeviceUtils.isInMultiWindow(activity) ? requireView() : activity.getWindow().getDecorView()).getHeight(); // Height is zero when the view is not yet displayed like after orientation change @@ -1873,13 +1873,14 @@ public final class VideoDetailFragment // from landscape to portrait every time. // Just turn on fullscreen mode in landscape orientation // or portrait & unlocked global orientation + final boolean isLandscape = DeviceUtils.isLandscape(requireContext()); if (DeviceUtils.isTablet(activity) - && (!globalScreenOrientationLocked(activity) || isLandscape())) { + && (!globalScreenOrientationLocked(activity) || isLandscape)) { player.toggleFullscreen(); return; } - final int newOrientation = isLandscape() + final int newOrientation = isLandscape ? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE; @@ -1951,15 +1952,17 @@ public final class VideoDetailFragment | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + // In multiWindow mode status bar is not transparent for devices with cutout // if I include this flag. So without it is better in this case - if (!isInMultiWindow()) { + final boolean isInMultiWindow = DeviceUtils.isInMultiWindow(activity); + if (!isInMultiWindow) { visibility |= View.SYSTEM_UI_FLAG_FULLSCREEN; } activity.getWindow().getDecorView().setSystemUiVisibility(visibility); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP - && (isInMultiWindow() || (isPlayerAvailable() && player.isFullscreen()))) { + && (isInMultiWindow || (isPlayerAvailable() && player.isFullscreen()))) { activity.getWindow().setStatusBarColor(Color.TRANSPARENT); activity.getWindow().setNavigationBarColor(Color.TRANSPARENT); } @@ -2031,15 +2034,6 @@ public final class VideoDetailFragment } } - public boolean isLandscape() { - return getResources().getDisplayMetrics().heightPixels < getResources() - .getDisplayMetrics().widthPixels; - } - - private boolean isInMultiWindow() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && activity.isInMultiWindowMode(); - } - /* * Means that the player fragment was swiped away via BottomSheetLayout * and is empty but ready for any new actions. See cleanUp() @@ -2222,7 +2216,7 @@ public final class VideoDetailFragment setOverlayElementsClickable(false); hideSystemUiIfNeeded(); // Conditions when the player should be expanded to fullscreen - if (isLandscape() + if (DeviceUtils.isLandscape(requireContext()) && isPlayerAvailable() && player.isPlaying() && !player.isFullscreen() diff --git a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java index 7a04ec22e..5b4b308d6 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java @@ -24,7 +24,6 @@ import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.IBinder; -import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -36,6 +35,7 @@ import androidx.core.content.ContextCompat; import org.schabi.newpipe.App; import org.schabi.newpipe.databinding.PlayerBinding; +import org.schabi.newpipe.util.DeviceUtils; import org.schabi.newpipe.util.ThemeHelper; import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; @@ -222,11 +222,8 @@ public final class MainPlayer extends Service { boolean isLandscape() { // DisplayMetrics from activity context knows about MultiWindow feature // while DisplayMetrics from app context doesn't - final DisplayMetrics metrics = (player != null - && player.getParentActivity() != null - ? player.getParentActivity().getResources() - : getResources()).getDisplayMetrics(); - return metrics.heightPixels < metrics.widthPixels; + return DeviceUtils.isLandscape(player != null && player.getParentActivity() != null + ? player.getParentActivity() : this); } @Nullable diff --git a/app/src/main/java/org/schabi/newpipe/util/DeviceUtils.java b/app/src/main/java/org/schabi/newpipe/util/DeviceUtils.java index 8d918c162..73bc4d6bb 100644 --- a/app/src/main/java/org/schabi/newpipe/util/DeviceUtils.java +++ b/app/src/main/java/org/schabi/newpipe/util/DeviceUtils.java @@ -11,6 +11,7 @@ import android.view.KeyEvent; import androidx.annotation.Dimension; import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat; import androidx.preference.PreferenceManager; @@ -130,4 +131,13 @@ public final class DeviceUtils { && !HI3798MV200 && !CVT_MT5886_EU_1G; } + + public static boolean isLandscape(final Context context) { + return context.getResources().getDisplayMetrics().heightPixels < context.getResources() + .getDisplayMetrics().widthPixels; + } + + public static boolean isInMultiWindow(final AppCompatActivity activity) { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && activity.isInMultiWindowMode(); + } } diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java index 539387082..563a67af4 100644 --- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java @@ -369,7 +369,7 @@ public final class NavigationHelper { // Starting directly in fullscreen if the previous player type was popup. if (playerType == MainPlayer.PlayerType.POPUP - && !detailFragment.isLandscape() + && !DeviceUtils.isLandscape(context) && PlayerHelper.globalScreenOrientationLocked(context)) { detailFragment.onScreenRotationButtonClicked(); } From c6316abbcec79704a7f13c60b679cc2a2e874255 Mon Sep 17 00:00:00 2001 From: Stypox Date: Sun, 28 Mar 2021 12:03:33 +0200 Subject: [PATCH 3/8] Fix opening directly fullscreen on tablets --- .../fragments/detail/VideoDetailFragment.java | 2 +- .../java/org/schabi/newpipe/player/Player.java | 17 +++++++++++++++++ .../schabi/newpipe/util/NavigationHelper.java | 10 +--------- 3 files changed, 19 insertions(+), 10 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 950430463..759ec3546 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 @@ -1109,7 +1109,7 @@ public final class VideoDetailFragment && PlayerHelper.isStartMainPlayerFullscreenEnabled(requireContext()) && !DeviceUtils.isLandscape(requireContext()) && PlayerHelper.globalScreenOrientationLocked(requireContext())) { - // open directly in fullscreen TODO does it work for large-land layouts? + // toggle landscape in order to open directly in fullscreen onScreenRotationButtonClicked(); } diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java index 10532c5eb..832c40cd3 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -621,6 +621,9 @@ public final class Player implements return; } + // needed for tablets, check the function for a better explanation + directlyOpenFullscreenIfNeeded(); + final PlaybackParameters savedParameters = retrievePlaybackParametersFromPrefs(this); final float playbackSpeed = savedParameters.speed; final float playbackPitch = savedParameters.pitch; @@ -743,6 +746,20 @@ public final class Player implements NavigationHelper.sendPlayerStartedEvent(context); } + private void directlyOpenFullscreenIfNeeded() { + if (fragmentListener != null + && PlayerHelper.isStartMainPlayerFullscreenEnabled(service) + && DeviceUtils.isTablet(service) + && videoPlayerSelected() + && PlayerHelper.globalScreenOrientationLocked(service)) { + // Open fullscreen on tablets where the option to have the main player start + // automatically in fullscreen mode is on. Rotating the device to landscape is already + // done in VideoDetailFragment when the thumbnail is clicked, and that's enough for + // phones, but not for tablets since the mini player can be also shown in landscape. + fragmentListener.onScreenRotationButtonClicked(); + } + } + private void initPlayback(@NonNull final PlayQueue queue, @RepeatMode final int repeatMode, final float playbackSpeed, diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java index 563a67af4..67043d808 100644 --- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java @@ -366,15 +366,7 @@ public final class NavigationHelper { if (switchingPlayers) { // Situation when user switches from players to main player. All needed data is // here, we can start watching (assuming newQueue equals playQueue). - - // Starting directly in fullscreen if the previous player type was popup. - if (playerType == MainPlayer.PlayerType.POPUP - && !DeviceUtils.isLandscape(context) - && PlayerHelper.globalScreenOrientationLocked(context)) { - detailFragment.onScreenRotationButtonClicked(); - } - // pass false to directlyFullscreenIfApplicable since that's handled just above here - detailFragment.openVideoPlayer(false); + detailFragment.openVideoPlayer(true); } else { detailFragment.selectAndLoadVideo(serviceId, url, title, playQueue); } From 520ac2e935e432b6fd412436760a5996af960428 Mon Sep 17 00:00:00 2001 From: Stypox Date: Tue, 27 Jul 2021 10:31:25 +0200 Subject: [PATCH 4/8] Fix bottom sheet state after automatic fullscreen --- .../newpipe/fragments/detail/VideoDetailFragment.java | 8 ++++++++ 1 file changed, 8 insertions(+) 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 759ec3546..8a5008aed 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 @@ -1109,6 +1109,14 @@ public final class VideoDetailFragment && PlayerHelper.isStartMainPlayerFullscreenEnabled(requireContext()) && !DeviceUtils.isLandscape(requireContext()) && PlayerHelper.globalScreenOrientationLocked(requireContext())) { + // Make sure the bottom sheet turns out expanded. When this code kicks in the bottom + // sheet could not have fully expanded yet, and thus be in the STATE_SETTLING state. + // When the activity is rotated, and its state is saved and then restored, the bottom + // sheet would forget what it was doing, since even if STATE_SETTLING is restored, it + // doesn't tell which state it was settling to, and thus the bottom sheet settles to + // STATE_COLLAPSED. This can be solved by manually setting the state that will be + // restored (i.e. bottomSheetState) to STATE_EXPANDED. + bottomSheetState = BottomSheetBehavior.STATE_EXPANDED; // toggle landscape in order to open directly in fullscreen onScreenRotationButtonClicked(); } From 1d935b46f9ca4b62f576e7a3637fb9c45a96017b Mon Sep 17 00:00:00 2001 From: Stypox Date: Tue, 27 Jul 2021 11:02:32 +0200 Subject: [PATCH 5/8] Open fullscreen when switching from popup to main player --- .../fragments/detail/VideoDetailFragment.java | 15 +++++++++++---- .../org/schabi/newpipe/util/NavigationHelper.java | 4 +++- 2 files changed, 14 insertions(+), 5 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 8a5008aed..3894fb71b 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 @@ -241,7 +241,7 @@ public final class VideoDetailFragment && isAutoplayEnabled() && player.getParentActivity() == null)) { autoPlayEnabled = true; // forcefully start playing - openVideoPlayer(true); + openVideoPlayerAutoFullscreen(); } } @@ -499,7 +499,7 @@ public final class VideoDetailFragment break; case R.id.detail_thumbnail_root_layout: autoPlayEnabled = true; // forcefully start playing - openVideoPlayer(true); + openVideoPlayerAutoFullscreen(); break; case R.id.detail_title_root_layout: toggleTitleAndSecondaryControls(); @@ -899,7 +899,7 @@ public final class VideoDetailFragment } if (isAutoplayEnabled()) { - openVideoPlayer(true); + openVideoPlayerAutoFullscreen(); } } }, throwable -> showError(new ErrorInfo(throwable, UserAction.REQUESTED_STREAM, @@ -1105,8 +1105,9 @@ public final class VideoDetailFragment } public void openVideoPlayer(final boolean directlyFullscreenIfApplicable) { + // Toggle to landscape orientation (which will then cause fullscreen mode) if we are not + // already in landscape and screen orientation is locked. if (directlyFullscreenIfApplicable - && PlayerHelper.isStartMainPlayerFullscreenEnabled(requireContext()) && !DeviceUtils.isLandscape(requireContext()) && PlayerHelper.globalScreenOrientationLocked(requireContext())) { // Make sure the bottom sheet turns out expanded. When this code kicks in the bottom @@ -1129,6 +1130,12 @@ public final class VideoDetailFragment } } + public void openVideoPlayerAutoFullscreen() { + // if the option to start directly fullscreen is enabled, openVideoPlayer will be called + // with directlyFullscreenIfApplicable=true and therefore open fullscreen if applicable + openVideoPlayer(PlayerHelper.isStartMainPlayerFullscreenEnabled(requireContext())); + } + private void openNormalBackgroundPlayer(final boolean append) { // See UI changes while remote playQueue changes if (!isPlayerAvailable()) { diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java index 67043d808..eba24020f 100644 --- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java @@ -366,7 +366,9 @@ public final class NavigationHelper { if (switchingPlayers) { // Situation when user switches from players to main player. All needed data is // here, we can start watching (assuming newQueue equals playQueue). - detailFragment.openVideoPlayer(true); + // Starting directly in fullscreen if the previous player type was popup. + detailFragment.openVideoPlayer(playerType == MainPlayer.PlayerType.POPUP + || PlayerHelper.isStartMainPlayerFullscreenEnabled(context)); } else { detailFragment.selectAndLoadVideo(serviceId, url, title, playQueue); } From cf9b482be25b412f183635cb0fc4bfc877c7d035 Mon Sep 17 00:00:00 2001 From: Stypox Date: Tue, 31 Aug 2021 11:10:52 +0200 Subject: [PATCH 6/8] Completely close player when changing stream w/o autoplay --- .../fragments/detail/VideoDetailFragment.java | 25 +++++++++++++------ .../org/schabi/newpipe/player/MainPlayer.java | 13 ++++------ 2 files changed, 23 insertions(+), 15 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 3894fb71b..6e94d2d0d 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 @@ -201,7 +201,7 @@ public final class VideoDetailFragment @Nullable private MainPlayer playerService; private Player player; - private PlayerHolder playerHolder = PlayerHolder.getInstance(); + private final PlayerHolder playerHolder = PlayerHolder.getInstance(); /*////////////////////////////////////////////////////////////////////////// // Service management @@ -762,7 +762,7 @@ public final class VideoDetailFragment private void setupFromHistoryItem(final StackItem item) { setAutoPlay(false); - hideMainPlayer(); + hideMainPlayerOnLoadingNewStream(); setInitialData(item.getServiceId(), item.getUrl(), item.getTitle() == null ? "" : item.getTitle(), item.getPlayQueue()); @@ -882,7 +882,7 @@ public final class VideoDetailFragment .observeOn(AndroidSchedulers.mainThread()) .subscribe(result -> { isLoading.set(false); - hideMainPlayer(); + hideMainPlayerOnLoadingNewStream(); if (result.getAgeLimit() != NO_AGE_LIMIT && !prefs.getBoolean( getString(R.string.show_age_restricted_content), false)) { hideAgeRestrictedContent(); @@ -1174,7 +1174,14 @@ public final class VideoDetailFragment ContextCompat.startForegroundService(activity, playerIntent); } - private void hideMainPlayer() { + /** + * When the video detail fragment is already showing details for a video and the user opens a + * new one, the video detail fragment changes all of its old data to the new stream, so if there + * is a video player currently open it should be hidden. This method does exactly that. If + * autoplay is enabled, the underlying player is not stopped completely, since it is going to + * be reused in a few milliseconds and the flickering would be annoying. + */ + private void hideMainPlayerOnLoadingNewStream() { if (!isPlayerServiceAvailable() || playerService.getView() == null || !player.videoPlayerSelected()) { @@ -1182,8 +1189,12 @@ public final class VideoDetailFragment } removeVideoPlayerView(); - playerService.stop(isAutoplayEnabled()); - playerService.getView().setVisibility(View.GONE); + if (isAutoplayEnabled()) { + playerService.stopForImmediateReusing(); + playerService.getView().setVisibility(View.GONE); + } else { + playerHolder.stopService(); + } } private PlayQueue setupPlayQueueForIntent(final boolean append) { @@ -1832,7 +1843,7 @@ public final class VideoDetailFragment || error.type == ExoPlaybackException.TYPE_UNEXPECTED) { // Properly exit from fullscreen toggleFullscreenIfInFullscreenMode(); - hideMainPlayer(); + hideMainPlayerOnLoadingNewStream(); } } diff --git a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java index 5b4b308d6..a9b9f4c87 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/MainPlayer.java @@ -133,32 +133,29 @@ public final class MainPlayer extends Service { return START_NOT_STICKY; } - public void stop(final boolean autoplayEnabled) { + public void stopForImmediateReusing() { if (DEBUG) { - Log.d(TAG, "stop() called"); + Log.d(TAG, "stopForImmediateReusing() called"); } if (!player.exoPlayerIsNull()) { player.saveWasPlaying(); + // Releases wifi & cpu, disables keepScreenOn, etc. - if (!autoplayEnabled) { - player.pause(); - } // We can't just pause the player here because it will make transition // from one stream to a new stream not smooth player.smoothStopPlayer(); player.setRecovery(); + // Android TV will handle back button in case controls will be visible // (one more additional unneeded click while the player is hidden) player.hideControls(0, 0); player.closeItemsList(); + // Notification shows information about old stream but if a user selects // a stream from backStack it's not actual anymore // So we should hide the notification at all. // When autoplay enabled such notification flashing is annoying so skip this case - if (!autoplayEnabled) { - NotificationUtil.getInstance().cancelNotificationAndStopForeground(this); - } } } From 3bc661f583266a857edbde585d7a54a440c0b55e Mon Sep 17 00:00:00 2001 From: Stypox Date: Tue, 31 Aug 2021 11:11:11 +0200 Subject: [PATCH 7/8] Fix null pointer exception in player initialization --- app/src/main/java/org/schabi/newpipe/player/Player.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java index 832c40cd3..63c31e082 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -675,6 +675,7 @@ public final class Player implements && isPlaybackResumeEnabled(this) && !samePlayQueue && !newQueue.isEmpty() + && newQueue.getItem() != null && newQueue.getItem().getRecoveryPosition() == PlayQueueItem.RECOVERY_UNSET) { databaseUpdateDisposable.add(recordManager.loadStreamState(newQueue.getItem()) .observeOn(AndroidSchedulers.mainThread()) From ed408b209499c05c73278debf9cabe8ffb4ab697 Mon Sep 17 00:00:00 2001 From: Stypox Date: Tue, 31 Aug 2021 11:28:34 +0200 Subject: [PATCH 8/8] Move fullscreen-related comments to javadocs --- .../fragments/detail/VideoDetailFragment.java | 19 +++++++++++++++---- .../org/schabi/newpipe/player/Player.java | 10 ++++++---- 2 files changed, 21 insertions(+), 8 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 6e94d2d0d..ecf235abc 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 @@ -1104,9 +1104,14 @@ public final class VideoDetailFragment } } + /** + * Opens the video player, in fullscreen if needed. In order to open fullscreen, the activity + * is toggled to landscape orientation (which will then cause fullscreen mode). + * + * @param directlyFullscreenIfApplicable whether to open fullscreen if we are not already + * in landscape and screen orientation is locked + */ public void openVideoPlayer(final boolean directlyFullscreenIfApplicable) { - // Toggle to landscape orientation (which will then cause fullscreen mode) if we are not - // already in landscape and screen orientation is locked. if (directlyFullscreenIfApplicable && !DeviceUtils.isLandscape(requireContext()) && PlayerHelper.globalScreenOrientationLocked(requireContext())) { @@ -1130,9 +1135,15 @@ public final class VideoDetailFragment } } + /** + * If the option to start directly fullscreen is enabled, calls + * {@link #openVideoPlayer(boolean)} with {@code directlyFullscreenIfApplicable = true}, so that + * if the user is not already in landscape and he has screen orientation locked the activity + * rotates and fullscreen starts. Otherwise, if the option to start directly fullscreen is + * disabled, calls {@link #openVideoPlayer(boolean)} with {@code directlyFullscreenIfApplicable + * = false}, hence preventing it from going directly fullscreen. + */ public void openVideoPlayerAutoFullscreen() { - // if the option to start directly fullscreen is enabled, openVideoPlayer will be called - // with directlyFullscreenIfApplicable=true and therefore open fullscreen if applicable openVideoPlayer(PlayerHelper.isStartMainPlayerFullscreenEnabled(requireContext())); } diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java index 63c31e082..dd5468f69 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -747,16 +747,18 @@ public final class Player implements NavigationHelper.sendPlayerStartedEvent(context); } + /** + * Open fullscreen on tablets where the option to have the main player start automatically in + * fullscreen mode is on. Rotating the device to landscape is already done in {@link + * VideoDetailFragment#openVideoPlayer(boolean)} when the thumbnail is clicked, and that's + * enough for phones, but not for tablets since the mini player can be also shown in landscape. + */ private void directlyOpenFullscreenIfNeeded() { if (fragmentListener != null && PlayerHelper.isStartMainPlayerFullscreenEnabled(service) && DeviceUtils.isTablet(service) && videoPlayerSelected() && PlayerHelper.globalScreenOrientationLocked(service)) { - // Open fullscreen on tablets where the option to have the main player start - // automatically in fullscreen mode is on. Rotating the device to landscape is already - // done in VideoDetailFragment when the thumbnail is clicked, and that's enough for - // phones, but not for tablets since the mini player can be also shown in landscape. fragmentListener.onScreenRotationButtonClicked(); } }