Exoplayer: How to Add button for full-screen video with exo player?

Created on 21 Sep 2016  路  18Comments  路  Source: google/ExoPlayer

I'm using exoPlayer to stream video to my app and so far works fine. What I would like to do now is to add some extra functionality such as a button on the bottom right edge to act as a "full-screen button".

But there are two problems. The first is that ExoPlayer doesn't seem to provide any Control class so you can simply add a button and override its functionality. What I guess is that I have to display that button on top of the video so I might have to wrap both in a FrameLayout and add gravity = bottom for the button or is there another way ?

The second problem is : if the user clicks the full-screen button what should I do next? Add another Fragment with the video view in full screen ? But how can I start the video from the point it was when user click the button and not start it from the beginning ? I can't find in exoPlayer anything relative to start from a specific time.

enhancement

Most helpful comment

@GeoffLedak I tried your solution and it's great, but it has some issues.

  • It has a strange behaviour when the app goes in background when the video is in fullscreen and returns to foreground, the video is gone and there's only an unstoppable ghost audio track.
  • It needs to keep the phone awake while playing.
  • If the enclosing Activity has an only portrait orientation, the resulting fullscreen video stays in portrait and doesn't rotate, to address this I think that using another Activity (that follows the Android immersive guidelines that @b95505017 linked) instead of a Dialog is a more universal solution.

I'll try to address these issues now and integrate your code but I think that this feature could eventually be part of the ExoPlayer library because it's an essential feature imho.

UPDATE

@GeoffLedak I've successfully implemented the feature by mixing your guide with this guide, I needed to have multiple PlayerView instances, so you can see my resulting code in this Gist.
I'm using the latest ExoPlayer version available, 2.7.0, where some of the classes are deprecated, thus the differences you can see in layout naming and classes used.

All 18 comments

+1

Probably the "easiest" way is to copy SimpleExoPlayerView and PlaybackControlView from exoplayer v2 to your project and add full-screen button with appropriate listener there. You should mirror behavior of the playPauseButton. I have done that with MediaPlayer and it worked :) but then you realize it's much better to make your custom views from stretch suitable for your use-case...
As for the second problem just set width and height of the view playing video to MATCH_PARENT and visibility View.GONE for all other views.

_NOTE_: This looks like stackoverflow material. You'll most likely find better luck there.

The best user experience may be integrating with this guide:
https://developer.android.com/design/patterns/fullscreen.html

+1

I am also looking for such solution

Any method available on player for show full screen icon on player controller ?

You can use a custom PlaybackControlView to add a fullscreen button to the Exoplayer controls.

To toggle the video to fullscreen, you can programmatically remove the SimpleExoPlayerView from your activity and add it to a new fullscreen dialog.

A walk-through is available here: https://geoffledak.com/blog/2017/09/11/how-to-add-a-fullscreen-toggle-button-to-exoplayer-in-android/

Cheers!

Thank you very much @GeoffLedak , I will test it on this week

@GeoffLedak I tried your solution and it's great, but it has some issues.

  • It has a strange behaviour when the app goes in background when the video is in fullscreen and returns to foreground, the video is gone and there's only an unstoppable ghost audio track.
  • It needs to keep the phone awake while playing.
  • If the enclosing Activity has an only portrait orientation, the resulting fullscreen video stays in portrait and doesn't rotate, to address this I think that using another Activity (that follows the Android immersive guidelines that @b95505017 linked) instead of a Dialog is a more universal solution.

I'll try to address these issues now and integrate your code but I think that this feature could eventually be part of the ExoPlayer library because it's an essential feature imho.

UPDATE

@GeoffLedak I've successfully implemented the feature by mixing your guide with this guide, I needed to have multiple PlayerView instances, so you can see my resulting code in this Gist.
I'm using the latest ExoPlayer version available, 2.7.0, where some of the classes are deprecated, thus the differences you can see in layout naming and classes used.

Hey @artemisia-absynthium , I'm kinda new to Android and I'm blowing my brains out trying to implement this simple feature. I pretty much shamelessly copy pasted your code but I'm stuck at this part.

// Create a new player if the player is null or
// we want to play a new video
// Do all the standard ExoPlayer code here...
// Prepare the player with the source.

Could you please tell me what exactly goes here instead of these comments? Everywhere I look I can only see code using SimpleExoPlayerView which seems to be different in implementation from PlayerView. I would greatly appreciate this. Thanks!

Nevermind, I'm dumb. This is what I replaced those comments with.

            BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
            TrackSelection.Factory videoTrackSelectionFactory = new     AdaptiveTrackSelection.Factory(bandwidthMeter);
            TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
            player = ExoPlayerFactory.newSimpleInstance(exoPlayerView.getContext(), trackSelector);
            RtmpDataSourceFactory rtmpDataSourceFactory = new RtmpDataSourceFactory();
            ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
            MediaSource videoSource = new ExtractorMediaSource(videoUri,
                    rtmpDataSourceFactory, extractorsFactory, null, null);

ExtractorMediaSource is still deprecated tho. Would like to know the replacement for that.

@ganesh3s3 , perfect! I commented out that part because it's sensibly different depending on use cases (such as video format you need to play, bandwidth management and so on).

As for the deprecation, according to the official documentation, you just need to use the ExtractorMediaSource.Factory instead of the constructor.

@artemisia-absynthium Thanks a bunch. It's working now.

ExtractorMediaSource.Factory mediaSourceFactory =
                    new ExtractorMediaSource.Factory(rtmpDataSourceFactory);

MediaSource videoSource = mediaSourceFactory
                    .setExtractorsFactory(extractorsFactory)
                    .createMediaSource(videoUri);

I believe adding totally self-contained fullscreen functionality into a PlayerView or PlayerControlView is sowewhat tricky, and such behavior is better (more easily?) managed with at least some coordination on activity level which is aware of the whole layout.

Also, meaning of a fullscreen layout may vary from use case to use case (visibility/behavior of system bars, etc.).

Some points that might be worth considering if fullscreen functionality is to be included:

  • Immersive and leanback modes and api level limitations on available system flags
  • behavior of system window insets
  • synchronizing visibility of player controls ui and system ui (status/nav bar) in response to user-interaction and auto-hide-after-timeout use cases
  • back button behavior; for .e.g. when in fullscreen, users may expect to exit fullscreen mode to where other non-video content is laid out, and not expect to end the Activity altogether
  • communicating fullscreen status (as considered by activity managing the layout) from external triggers (e.g. back button press) to the PlayerView (so it may update enter/exit fullscreen icons accordingly)
  • callback listeners for communicating/broadcasting user interaction (e.g. pressing fullscreen button) so the registered listener/activity may implement custom behavior (change layout params, hiding other layout, changing window flags, etc.)
  • how to hide/unhide non-video layout when entering/exiting fullscreen mode

Thanks for your thoughts! It's definitely tricky to pull off in a self contained way, particularly on earlier API levels. We do want to at least add a fullscreen icon into PlayerView, so application developers don't need to do UI bit themselves. What the icon will do when tapped is currently under discussion. One option is just to invoke an application provided callback and therefore leave it to application code to take appropriate action (in which case we'd only display the icon if a callback has been set).

That's close to how I tried to implement fullscreen behavior. With the main target of having the PlayerView's fullscreen icon reflect the correct fullscreen status (as considered by application) I believe it's better for the PlayerView to

  • dispatch a user interaction as an event for the application to handle
  • accept fullscreen status from the application

Mainly I have:

  • a FullscreenActionListener interface. The listener will be notified (when user clicks on enter/exit fullscreen icon) and will return value indicating if it handled the action. The enter/exit icon will be updated based on this return value.
public interface FullscreenActionListener {
        /**
         * @return if enter or exit fullscreen action was handled
         */
        boolean onFullscreenAction(boolean enterFullscreen);
}
  • a VisibilityListener for notifying activity/listener of controller visibility (already present in exoplayer as PlaybackControlView.VisibilityListener). This is specially useful when the activity also needs to hide system ui and/or enter immersive mode at the same time the player ui controls are hidden (as suggested in official guide)
  • public void setFullscreenState(boolean fullscreen);
    This helps to notify the PlayerView/PlayerControlView (to update the fullscreen icon) if the activity had to enter or exit the fullscreen mode due to some trigger other than the user pressing the fullscreen button (e.g. 1. orientation changes -- partialscreen in portrait, fullscreen in landscape use case; 2. back button press in fullscreen mode).

A pattern similar to FullscreenActionListener can be used for other events/use cases that may be handled outside of the PlayerView, but that's probably more application specific.

I'm not sure if this covers all possible fullscreen use-cases and other system-ui visibility quirks but should suffice for a basic and extensible solution. Hth :)

In my case was more difficult because my video is on a bottomSheet. I tested two implementations, with DialogFragment and Activity. The first works very well, but i had problem with Picture-in_Picture (Android 8). I think the option with Activity is still the best. You have more controls of Life Cicle.

Was this page helpful?
0 / 5 - 0 ratings