How to Add a Fullscreen Toggle Button to ExoPlayer in Android
Download the complete source code for this project:
- as a ZIP file
- view on Github
ExoPlayer is a great alternative to Android’s MediaPlayer API and adds support for HLS, DASH, and SmoothStreaming adaptive playback. While it is far superior to Android’s default media player, it lacks the ability to easily toggle a video in and out of a full screen mode. Today I’ll show you a solution to this problem.
Expand! Shrink!
Rather than creating a new activity, this solution uses the magic of a fullscreen dialog. When the video is toggled into fullscreen mode, the SimpleExoPlayerView
will be removed from the activity layout, and added to a new dialog. The transition between views is very fast, and there is no audio stuttering or buffering when streaming video.
The XML
First we’ll add the fullscreen toggle button to the Exoplayer controls. This can be done by overriding the defaultĀ PlaybackControlView
layout. To do this, copy the exo_playback_control_view.xml file from the exoplayer-ui package into your project’s layout directory. You’ll also want some image assets to use for the expand and shrink icons. You can download the icons used in this example here:
– ic_fullscreen_expand.png | |
– ic_fullscreen_shrink.png |
Ideally, you’d want different sized images for different screen densities, but for this example you can just copy these assets into your project’s drawable directory.
Next, we’ll edit the exo_playback_control_view.xml
file. Add the following to the second horizontal LinearLayout
. This code should go towards the bottom of the file, after the exo_duration
TextView
and before the second-to-last closing </LinearLayout>
tag:
<FrameLayout android:id="@+id/exo_fullscreen_button" android:layout_width="32dp" android:layout_height="32dp" android:layout_gravity="right"> <ImageView android:id="@+id/exo_fullscreen_icon" android:layout_width="18dp" android:layout_height="18dp" android:layout_gravity="center" android:adjustViewBounds="true" android:scaleType="fitCenter" android:src="@drawable/ic_fullscreen_expand"/> </FrameLayout>
Add The Controller Id
Now copy the exo_simple_player_view.xml file into your project’s layout directory. Add the following towards the bottom of the file, between the exo_controller_placeholder
View and the exo_overlay
FrameLayout:
<com.google.android.exoplayer2.ui.PlaybackControlView android:id="@id/exo_controller" android:layout_width="match_parent" android:layout_height="match_parent" />
This step is necessary in order to get a reference to the PlayBackControlView
from our activity by calling findViewById on the SimpleExoPlayerView
object (more on this later.)
Add The Player View To MainActivity’s Layout
To finish up the XML, we’ll add SimpleExoPlayerView to our activity. Inside of activity_main.xml, add the following:
<FrameLayout android:id="@+id/main_media_frame" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#000000"> <com.google.android.exoplayer2.ui.SimpleExoPlayerView android:id="@+id/exoplayer" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" /> </FrameLayout>
Adjust the FrameLayout’s width and height to your liking. The sample project assigns the layout a height of 0dp with a weight of 0.5 so it will fill half of the screen.
We wrap the SimpleExoPlayerView in a FrameLayout so that the view can be removed and re-added when the video is toggled in and out of full screen.
The Java
Ok, onto the Java code. Create a Dialog member variable called mFullScreenDialog. When initializing it, override the dialog’s onBackPressed() method:
private void initFullscreenDialog() { mFullScreenDialog = new Dialog(this, android.R.style.Theme_Black_NoTitleBar_Fullscreen) { public void onBackPressed() { if (mExoPlayerFullscreen) closeFullscreenDialog(); super.onBackPressed(); } }; }
This allows the user to exit fullscreen mode by either pressing the shrink button in the lower right of their screen, or by using their device’s back button. Also notice that we passed the android.R.style.Theme_Black_NoTitleBar_Fullscreen
style into the dialog’s constructor. This will make the dialog fill the entire screen when it’s shown.
Entering Fullscreen
Next, create a method called openFullscreenDialog()
. This method programmatically removes the SimpleExoPlayerView from the activity, adds a new instance of the view to the fullscreen dialog, and shows the dialog:
private void openFullscreenDialog() { ((ViewGroup) mExoPlayerView.getParent()).removeView(mExoPlayerView); mFullScreenDialog.addContentView(mExoPlayerView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); mFullScreenIcon.setImageDrawable(ContextCompat.getDrawable(MainActivity.this, R.drawable.ic_fullscreen_skrink)); mExoPlayerFullscreen = true; mFullScreenDialog.show(); }
Exiting Fullscreen
Now create a method called closeFullscreenDialog()
. This method adds a new SimpleExoPlayerView to the activity, removes the view from the fullscreen dialog, and dismisses the dialog:
private void closeFullscreenDialog() { ((ViewGroup) mExoPlayerView.getParent()).removeView(mExoPlayerView); ((FrameLayout) findViewById(R.id.main_media_frame)).addView(mExoPlayerView); mExoPlayerFullscreen = false; mFullScreenDialog.dismiss(); mFullScreenIcon.setImageDrawable(ContextCompat.getDrawable(MainActivity.this, R.drawable.ic_fullscreen_expand)); }
Initializing The Fullscreen Button
Finally, create a method to initialize the fullscreen button. In order to get a reference to the button, we first need a reference to the player’s PlaybackControlView. To do this, we call mExoPlayerView.findViewById(R.id.exo_controller)
. We added a view with this id earlier to exo_simple_player_view.xml
.
private void initFullscreenButton() { PlaybackControlView controlView = mExoPlayerView.findViewById(R.id.exo_controller); mFullScreenIcon = controlView.findViewById(R.id.exo_fullscreen_icon); mFullScreenButton = controlView.findViewById(R.id.exo_fullscreen_button); mFullScreenButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (!mExoPlayerFullscreen) openFullscreenDialog(); else closeFullscreenDialog(); } }); }
To understand why a view with this specific id is necessary, we can take a look at the source code of SimpleExoPlayerView
. Inside the view’s constructor we see the following:
PlaybackControlView customController = (PlaybackControlView) findViewById(R.id.exo_controller); ... if (customController != null) { this.controller = customController; } ... else { this.controller = null; }
If this id isn’t found, the PlaybackControlView is created elsewhere programmatically.
That’s It!
That should be everything you need to add a fullscreen mode to an existing Exoplayer implementation. If you need further examples of how to initialize Exoplayer and tie everything together, you can view the complete source code for the activity here, or download the complete project on GitHub.