-
-
Save artemisia-absynthium/e2333a58695dfa7e7eeed62193de8c26 to your computer and use it in GitHub Desktop.
<?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> |
... | |
<activity | |
android:name=".FullscreenVideoActivity" | |
android:configChanges="orientation|keyboardHidden|screenSize" | |
android:label="@string/app_name" | |
android:theme="@style/FullscreenTheme" /> | |
... |
... | |
<color name="black_overlay">#66000000</color> | |
... |
<?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> |
<?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> |
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); | |
} | |
} | |
} |
// 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); | |
} | |
} |
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); | |
} | |
}); | |
} | |
} |
... | |
<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. Thanks for your contribution. I have successful implemented the full screen feature in my app base on your tutorial.
But I'm stuck on adding a custom Player.EventListener. I created an instance of Player.EventListener in my MainActivity, and add it to the ExoPlayerViewManager. But when I play video, it never goes to the eventListener that I've added.
I've debugged, the eventListener was not null, it was added to the ExoPlayerViewManager successfully, but still didn't know why it never reaches to the code that I implement in my eventListener.
If you guys did face this issue, please help me. Thank you.
I try implement this, but I got a problem, PlayerView first time start ok, but after tap fullscreen button and then tap to go back, PlayerView set the background to black and at background just playing audio witout playing the video.
MY CODE
https://github.com/carlosesteven/exo_player_full_screen
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
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???
I try implement this, but I got a problem, PlayerView first time start ok, but after tap fullscreen button and then tap to go back, PlayerView set the background to black and at background just playing audio witout playing the video.
MY CODE
https://github.com/carlosesteven/exo_player_full_screen
SCREENSHOT