Last active
November 19, 2022 10:34
-
-
Save artemisia-absynthium/e2333a58695dfa7e7eeed62193de8c26 to your computer and use it in GitHub Desktop.
Android Exoplayer fullscreen feature
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:id="@+id/enclosing_layout" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:background="@android:color/black" | |
tools:context=".FullscreenVideoActivity"> | |
<com.google.android.exoplayer2.ui.PlayerView | |
android:id="@+id/player_view" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" /> | |
</FrameLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
<activity | |
android:name=".FullscreenVideoActivity" | |
android:configChanges="orientation|keyboardHidden|screenSize" | |
android:label="@string/app_name" | |
android:theme="@style/FullscreenTheme" /> | |
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
<color name="black_overlay">#66000000</color> | |
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_gravity="bottom" | |
android:background="#CC000000" | |
android:layoutDirection="ltr" | |
android:orientation="vertical"> | |
<LinearLayout | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:gravity="center" | |
android:orientation="horizontal" | |
android:paddingTop="4dp"> | |
<ImageButton | |
android:id="@id/exo_prev" | |
style="@style/ExoMediaButton.Previous" /> | |
<ImageButton | |
android:id="@id/exo_rew" | |
style="@style/ExoMediaButton.Rewind" /> | |
<ImageButton | |
android:id="@id/exo_shuffle" | |
style="@style/ExoMediaButton.Shuffle" /> | |
<ImageButton | |
android:id="@id/exo_repeat_toggle" | |
style="@style/ExoMediaButton" /> | |
<ImageButton | |
android:id="@id/exo_play" | |
style="@style/ExoMediaButton.Play" /> | |
<ImageButton | |
android:id="@id/exo_pause" | |
style="@style/ExoMediaButton.Pause" /> | |
<ImageButton | |
android:id="@id/exo_ffwd" | |
style="@style/ExoMediaButton.FastForward" /> | |
<ImageButton | |
android:id="@id/exo_next" | |
style="@style/ExoMediaButton.Next" /> | |
</LinearLayout> | |
<LinearLayout | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_marginTop="4dp" | |
android:gravity="center_vertical" | |
android:orientation="horizontal"> | |
<TextView | |
android:id="@id/exo_position" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:includeFontPadding="false" | |
android:paddingLeft="4dp" | |
android:paddingRight="4dp" | |
android:textColor="#FFBEBEBE" | |
android:textSize="14sp" | |
android:textStyle="bold" /> | |
<com.google.android.exoplayer2.ui.DefaultTimeBar | |
android:id="@id/exo_progress" | |
android:layout_width="0dp" | |
android:layout_height="26dp" | |
android:layout_weight="1" /> | |
<TextView | |
android:id="@id/exo_duration" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:includeFontPadding="false" | |
android:paddingLeft="4dp" | |
android:paddingRight="4dp" | |
android:textColor="#FFBEBEBE" | |
android:textSize="14sp" | |
android:textStyle="bold" /> | |
<FrameLayout | |
android:id="@+id/exo_fullscreen_button" | |
android:layout_width="32dp" | |
android:layout_height="wrap_content" | |
android:layout_gravity="right"> | |
<ImageView | |
android:id="@+id/exo_fullscreen_icon" | |
android:layout_width="40dp" | |
android:layout_height="40dp" | |
android:layout_gravity="center" | |
android:adjustViewBounds="true" | |
android:scaleType="fitCenter" | |
app:srcCompat="@drawable/ic_fullscreen" /> | |
</FrameLayout> | |
</LinearLayout> | |
</LinearLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<merge xmlns:android="http://schemas.android.com/apk/res/android"> | |
<com.google.android.exoplayer2.ui.AspectRatioFrameLayout | |
android:id="@id/exo_content_frame" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:layout_gravity="center"> | |
<!-- Video surface will be inserted as the first child of the content frame. --> | |
<View | |
android:id="@id/exo_shutter" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:background="@android:color/black" /> | |
<ImageView | |
android:id="@id/exo_artwork" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:scaleType="fitXY" /> | |
<com.google.android.exoplayer2.ui.SubtitleView | |
android:id="@id/exo_subtitles" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" /> | |
</com.google.android.exoplayer2.ui.AspectRatioFrameLayout> | |
<FrameLayout | |
android:id="@id/exo_overlay" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" /> | |
<com.google.android.exoplayer2.ui.PlayerControlView | |
android:id="@id/exo_controller" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" /> | |
</merge> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ExoPlayerViewManager { | |
private static final String TAG = "ExoPlayerViewManager"; | |
public static final String EXTRA_VIDEO_URI = "video_uri"; | |
private static Map<String, ExoPlayerViewManager> instances = new HashMap<>(); | |
private Uri videoUri; | |
public static ExoPlayerViewManager getInstance(String videoUri) { | |
ExoPlayerViewManager instance = instances.get(videoUri); | |
if (instance == null) { | |
instance = new ExoPlayerViewManager(videoUri); | |
instances.put(videoUri, instance); | |
} | |
return instance; | |
} | |
private SimpleExoPlayer player; | |
private boolean isPlayerPlaying; | |
private ExoPlayerViewManager(String videoUri) { | |
this.videoUri = Uri.parse(videoUri); | |
} | |
public void prepareExoPlayer(Context context, PlayerView exoPlayerView) { | |
if (context == null || exoPlayerView == null) { | |
return; | |
} | |
if (player == null) { | |
// 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. | |
player.prepare(videoSource); | |
} | |
player.clearVideoSurface(); | |
player.setVideoSurfaceView((SurfaceView) exoPlayerView.getVideoSurfaceView()); | |
player.seekTo(player.getCurrentPosition() + 1); | |
exoPlayerView.setPlayer(player); | |
} | |
public void releaseVideoPlayer() { | |
if (player != null) { | |
player.release(); | |
} | |
player = null; | |
} | |
public void goToBackground() { | |
if (player != null) { | |
isPlayerPlaying = player.getPlayWhenReady(); | |
player.setPlayWhenReady(false); | |
} | |
} | |
public void goToForeground() { | |
if (player != null) { | |
player.setPlayWhenReady(isPlayerPlaying); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Fullscreen related code taken from Android Studio blueprint | |
public class FullscreenVideoActivity extends AppCompatActivity { | |
/** | |
* Some older devices needs a small delay between UI widget updates | |
* and a change of the status and navigation bar. | |
*/ | |
private static final int UI_ANIMATION_DELAY = 300; | |
private final Handler mHideHandler = new Handler(); | |
private View mContentView; | |
private final Runnable mHidePart2Runnable = new Runnable() { | |
@SuppressLint("InlinedApi") | |
@Override | |
public void run() { | |
// Delayed removal of status and navigation bar | |
// Note that some of these constants are new as of | |
// API 19 (KitKat). It is safe to use them, as they are inlined | |
// at compile-time and do nothing on earlier devices. | |
mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | |
| View.SYSTEM_UI_FLAG_FULLSCREEN | |
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE | |
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | |
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | |
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); | |
} | |
}; | |
private final Runnable mHideRunnable = new Runnable() { | |
@Override | |
public void run() { | |
hide(); | |
} | |
}; | |
private String mVideoUri; | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_fullscreen_video); | |
mContentView = findViewById(R.id.enclosing_layout); | |
PlayerView playerView = findViewById(R.id.player_view); | |
mVideoUri = getIntent().getStringExtra(ExoPlayerViewManager.EXTRA_VIDEO_URI); | |
ExoPlayerViewManager.getInstance(mVideoUri) | |
.prepareExoPlayer(this, playerView); | |
// Set the fullscreen button to "close fullscreen" icon | |
View controlView = playerView.findViewById(R.id.exo_controller); | |
ImageView fullscreenIcon = controlView.findViewById(R.id.exo_fullscreen_icon); | |
fullscreenIcon.setImageResource(R.drawable.exo_controls_fullscreen_exit); | |
controlView.findViewById(R.id.exo_fullscreen_button) | |
.setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
finish(); | |
} | |
}); | |
} | |
@Override | |
public void onResume() { | |
super.onResume(); | |
ExoPlayerViewManager.getInstance(mVideoUri).goToForeground(); | |
} | |
@Override | |
public void onPause() { | |
super.onPause(); | |
ExoPlayerViewManager.getInstance(mVideoUri).goToBackground(); | |
} | |
@Override | |
public void onPostCreate(Bundle savedInstanceState) { | |
super.onPostCreate(savedInstanceState); | |
// Trigger the initial hide() shortly after the activity has been | |
// created, to briefly hint to the user that UI controls | |
// are available. | |
delayedHide(); | |
} | |
private void hide() { | |
// Schedule a runnable to remove the status and navigation bar after a delay | |
mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY); | |
} | |
/** | |
* Schedules a call to hide() in delay milliseconds, canceling any | |
* previously scheduled calls. | |
*/ | |
private void delayedHide() { | |
mHideHandler.removeCallbacks(mHideRunnable); | |
mHideHandler.postDelayed(mHideRunnable, 100); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class MyActivity extends AppCompatActivity { | |
private List<String> mVideoUrls; | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
// Your activity setup code... | |
for (String videoUrl : mVideoUrls) { | |
setupPlayerView(videoView, videoUrl); | |
} | |
} | |
@Override | |
public void onResume() { | |
super.onResume(); | |
for (String videoUrl : mVideoUrls) { | |
ExoPlayerViewManager.getInstance(videoUrl).goToForeground(); | |
} | |
} | |
@Override | |
public void onPause() { | |
super.onPause(); | |
for (String videoUrl : mVideoUrls) { | |
ExoPlayerViewManager.getInstance(videoUrl).goToBackground(); | |
} | |
} | |
@Override | |
public void onDestroyView() { | |
super.onDestroyView(); | |
for (String videoUrl : mVideoUrls) { | |
ExoPlayerViewManager.getInstance(videoUrl).releaseVideoPlayer(); | |
} | |
} | |
private void setupPlayerView(final PlayerView videoView, final String videoUrl) { | |
ExoPlayerViewManager.getInstance(videoUrl).prepareExoPlayer(getContext(), videoView); | |
ExoPlayerViewManager.getInstance(videoUrl).goToForeground(); | |
View controlView = videoView.findViewById(R.id.exo_controller); | |
controlView.findViewById(R.id.exo_fullscreen_button) | |
.setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
Intent intent = new Intent(getContext(), FullscreenVideoActivity.class); | |
intent.putExtra(ExoPlayerViewManager.EXTRA_VIDEO_URI, videoUrl); | |
getActivity().startActivity(intent); | |
} | |
}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
<style name="FullscreenTheme" parent="AppTheme"> | |
<item name="android:actionBarStyle">@style/FullscreenActionBarStyle</item> | |
<item name="android:windowActionBarOverlay">true</item> | |
<item name="android:windowBackground">@null</item> | |
</style> | |
<style name="FullscreenActionBarStyle" parent="Widget.AppCompat.ActionBar"> | |
<item name="android:background">@color/black_overlay</item> | |
</style> | |
... |
Hi, I faced this issue. You can try to add these lines of code in onResume in MainActivity before calling gotoForeground():
ExoPlayerVideoHandler.getInstance() .prepareExoPlayerForUri(rootView.getContext(), Uri.parse(videoUrl), exoPlayerView);
You can read more in this article: https://medium.com/tall-programmer/fullscreen-functionality-with-android-exoplayer-5fddad45509f
ExoPlayerViewManager.getInstance( videoUrl ) .prepareExoPlayer(this, videoView);
That fixed my problem, thanks.
Thanks for your contribution. It works for me~
can we open video in fragment full screen using this library???
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, I faced this issue. You can try to add these lines of code in onResume in MainActivity before calling gotoForeground():
ExoPlayerVideoHandler.getInstance() .prepareExoPlayerForUri(rootView.getContext(), Uri.parse(videoUrl), exoPlayerView);
You can read more in this article: https://medium.com/tall-programmer/fullscreen-functionality-with-android-exoplayer-5fddad45509f