@@ -180,6 +180,8 @@ public final class VideoDetailFragment
180180 @ State
181181 int bottomSheetState = BottomSheetBehavior .STATE_EXPANDED ;
182182 @ State
183+ int lastStableBottomSheetState = BottomSheetBehavior .STATE_EXPANDED ;
184+ @ State
183185 protected boolean autoPlayEnabled = true ;
184186
185187 @ Nullable
@@ -269,7 +271,7 @@ public static VideoDetailFragment getInstance(final int serviceId,
269271
270272 public static VideoDetailFragment getInstanceInCollapsedState () {
271273 final VideoDetailFragment instance = new VideoDetailFragment ();
272- instance .bottomSheetState = BottomSheetBehavior .STATE_COLLAPSED ;
274+ instance .updateBottomSheetState ( BottomSheetBehavior .STATE_COLLAPSED ) ;
273275 return instance ;
274276 }
275277
@@ -503,12 +505,18 @@ public void onClick(final View v) {
503505 }
504506 break ;
505507 case R .id .detail_thumbnail_root_layout :
506- autoPlayEnabled = true ; // forcefully start playing
507- // FIXME Workaround #7427
508- if (isPlayerAvailable ()) {
509- player .setRecovery ();
508+ // make sure not to open any player if there is nothing currently loaded!
509+ // FIXME removing this `if` causes the player service to start correctly, then stop,
510+ // then restart badly without calling `startForeground()`, causing a crash when
511+ // later closing the detail fragment
512+ if (currentInfo != null ) {
513+ autoPlayEnabled = true ; // forcefully start playing
514+ // FIXME Workaround #7427
515+ if (isPlayerAvailable ()) {
516+ player .setRecovery ();
517+ }
518+ openVideoPlayerAutoFullscreen ();
510519 }
511- openVideoPlayerAutoFullscreen ();
512520 break ;
513521 case R .id .detail_title_root_layout :
514522 toggleTitleAndSecondaryControls ();
@@ -1170,7 +1178,7 @@ public void openVideoPlayer(final boolean directlyFullscreenIfApplicable) {
11701178 // doesn't tell which state it was settling to, and thus the bottom sheet settles to
11711179 // STATE_COLLAPSED. This can be solved by manually setting the state that will be
11721180 // restored (i.e. bottomSheetState) to STATE_EXPANDED.
1173- bottomSheetState = BottomSheetBehavior .STATE_EXPANDED ;
1181+ updateBottomSheetState ( BottomSheetBehavior .STATE_EXPANDED ) ;
11741182 // toggle landscape in order to open directly in fullscreen
11751183 onScreenRotationButtonClicked ();
11761184 }
@@ -1220,7 +1228,7 @@ private void openMainPlayer() {
12201228 }
12211229
12221230 final PlayQueue queue = setupPlayQueueForIntent (false );
1223- addVideoPlayerView ();
1231+ tryAddVideoPlayerView ();
12241232
12251233 final Intent playerIntent = NavigationHelper .getPlayerIntent (requireContext (),
12261234 PlayerService .class , queue , true , autoPlayEnabled );
@@ -1301,21 +1309,33 @@ private boolean isAutoplayEnabled() {
13011309 && PlayerHelper .isAutoplayAllowedByUser (requireContext ());
13021310 }
13031311
1304- private void addVideoPlayerView () {
1305- if (!isPlayerAvailable () || getView () == null ) {
1306- return ;
1312+ private void tryAddVideoPlayerView () {
1313+ if (isPlayerAvailable () && getView () != null ) {
1314+ // Setup the surface view height, so that it fits the video correctly; this is done also
1315+ // here, and not only in the Handler, to avoid a choppy fullscreen rotation animation.
1316+ setHeightThumbnail ();
13071317 }
1308- setHeightThumbnail ();
13091318
1310- // Prevent from re-adding a view multiple times
1311- new Handler (Looper .getMainLooper ()).post (() ->
1312- player .UIs ().get (MainPlayerUi .class ).ifPresent (playerUi -> {
1313- if (binding != null ) {
1314- playerUi .removeViewFromParent ();
1315- binding .playerPlaceholder .addView (playerUi .getBinding ().getRoot ());
1316- playerUi .setupVideoSurfaceIfNeeded ();
1317- }
1318- }));
1319+ // do all the null checks in the posted lambda, too, since the player, the binding and the
1320+ // view could be set or unset before the lambda gets executed on the next main thread cycle
1321+ new Handler (Looper .getMainLooper ()).post (() -> {
1322+ if (!isPlayerAvailable () || getView () == null ) {
1323+ return ;
1324+ }
1325+
1326+ // setup the surface view height, so that it fits the video correctly
1327+ setHeightThumbnail ();
1328+
1329+ player .UIs ().get (MainPlayerUi .class ).ifPresent (playerUi -> {
1330+ // sometimes binding would be null here, even though getView() != null above u.u
1331+ if (binding != null ) {
1332+ // prevent from re-adding a view multiple times
1333+ playerUi .removeViewFromParent ();
1334+ binding .playerPlaceholder .addView (playerUi .getBinding ().getRoot ());
1335+ playerUi .setupVideoSurfaceIfNeeded ();
1336+ }
1337+ });
1338+ });
13191339 }
13201340
13211341 private void removeVideoPlayerView () {
@@ -1784,7 +1804,7 @@ private void showPlaybackProgress(final long progress, final long duration) {
17841804
17851805 @ Override
17861806 public void onViewCreated () {
1787- addVideoPlayerView ();
1807+ tryAddVideoPlayerView ();
17881808 }
17891809
17901810 @ Override
@@ -1926,7 +1946,7 @@ public void onFullscreenStateChanged(final boolean fullscreen) {
19261946 }
19271947 scrollToTop ();
19281948
1929- addVideoPlayerView ();
1949+ tryAddVideoPlayerView ();
19301950 }
19311951
19321952 @ Override
@@ -2272,7 +2292,9 @@ private void setupBottomPlayer() {
22722292
22732293 final FrameLayout bottomSheetLayout = activity .findViewById (R .id .fragment_player_holder );
22742294 bottomSheetBehavior = BottomSheetBehavior .from (bottomSheetLayout );
2275- bottomSheetBehavior .setState (bottomSheetState );
2295+ bottomSheetBehavior .setState (lastStableBottomSheetState );
2296+ updateBottomSheetState (lastStableBottomSheetState );
2297+
22762298 final int peekHeight = getResources ().getDimensionPixelSize (R .dimen .mini_player_height );
22772299 if (bottomSheetState != BottomSheetBehavior .STATE_HIDDEN ) {
22782300 manageSpaceAtTheBottom (false );
@@ -2288,7 +2310,7 @@ private void setupBottomPlayer() {
22882310 bottomSheetCallback = new BottomSheetBehavior .BottomSheetCallback () {
22892311 @ Override
22902312 public void onStateChanged (@ NonNull final View bottomSheet , final int newState ) {
2291- bottomSheetState = newState ;
2313+ updateBottomSheetState ( newState ) ;
22922314
22932315 switch (newState ) {
22942316 case BottomSheetBehavior .STATE_HIDDEN :
@@ -2429,4 +2451,12 @@ public Optional<View> getRoot() {
24292451 return player .UIs ().get (VideoPlayerUi .class )
24302452 .map (playerUi -> playerUi .getBinding ().getRoot ());
24312453 }
2454+
2455+ private void updateBottomSheetState (final int newState ) {
2456+ bottomSheetState = newState ;
2457+ if (newState != BottomSheetBehavior .STATE_DRAGGING
2458+ && newState != BottomSheetBehavior .STATE_SETTLING ) {
2459+ lastStableBottomSheetState = newState ;
2460+ }
2461+ }
24322462}
0 commit comments