add fullscreen activity
This commit is contained in:
parent
dbf1a4e034
commit
94bceb472b
@ -0,0 +1,107 @@
|
||||
package com.brentvatne.exoplayer;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.brentvatne.react.R;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.ui.PlayerControlView;
|
||||
|
||||
public class ExoPlayerFullscreenVideoActivity extends AppCompatActivity implements ReactExoplayerView.FullScreenDelegate {
|
||||
public static final String EXTRA_ID = "extra_id";
|
||||
public static final String EXTRA_IS_PLAYING = "extra_is_playing";
|
||||
|
||||
private int id;
|
||||
private PlayerControlView playerControlView;
|
||||
private SimpleExoPlayer player;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.exo_player_fullscreen_video);
|
||||
id = getIntent().getIntExtra(EXTRA_ID, -1);
|
||||
player = ReactExoplayerView.getViewInstance(id).getPlayer();
|
||||
|
||||
ExoPlayerView playerView = findViewById(R.id.player_view);
|
||||
playerView.setPlayer(player);
|
||||
playerView.setOnClickListener(v -> togglePlayerControlVisibility());
|
||||
|
||||
playerControlView = findViewById(R.id.player_controls);
|
||||
playerControlView.setPlayer(player);
|
||||
// Set the fullscreen button to "close fullscreen" icon
|
||||
ImageView fullscreenIcon = playerControlView.findViewById(R.id.exo_fullscreen_icon);
|
||||
fullscreenIcon.setImageResource(R.drawable.exo_controls_fullscreen_exit);
|
||||
playerControlView.findViewById(R.id.exo_fullscreen_button)
|
||||
.setOnClickListener(v -> finish());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
boolean isPlaying = getIntent().getBooleanExtra(EXTRA_IS_PLAYING, false);
|
||||
player.setPlayWhenReady(isPlaying);
|
||||
ReactExoplayerView.getViewInstance(id).registerFullScreenDelegate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
boolean isPlaying = player.getPlayWhenReady() && player.getPlaybackState() == Player.STATE_READY;
|
||||
ReactExoplayerView.getViewInstance(id).setPausedModifier(!isPlaying);
|
||||
player.setPlayWhenReady(false);
|
||||
ReactExoplayerView.getViewInstance(id).registerFullScreenDelegate(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
if (hasFocus) {
|
||||
hideSystemUI();
|
||||
}
|
||||
}
|
||||
|
||||
private void togglePlayerControlVisibility() {
|
||||
if (playerControlView.isVisible()) {
|
||||
playerControlView.hide();
|
||||
} else {
|
||||
playerControlView.show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables regular immersive mode.
|
||||
*/
|
||||
private void hideSystemUI() {
|
||||
View decorView = getWindow().getDecorView();
|
||||
decorView.setSystemUiVisibility(
|
||||
View.SYSTEM_UI_FLAG_IMMERSIVE
|
||||
// Set the content to appear under the system bars so that the
|
||||
// content doesn't resize when the system bars hide and show.
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
// Hide the nav bar and status bar
|
||||
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the system bars by removing all the flags
|
||||
* except for the ones that make the content appear under the system bars.
|
||||
*/
|
||||
private void showSystemUI() {
|
||||
View decorView = getWindow().getDecorView();
|
||||
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeFullScreen() {
|
||||
finish();
|
||||
}
|
||||
}
|
@ -120,9 +120,6 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
* @param player The {@link SimpleExoPlayer} to use.
|
||||
*/
|
||||
public void setPlayer(SimpleExoPlayer player) {
|
||||
if (this.player == player) {
|
||||
return;
|
||||
}
|
||||
if (this.player != null) {
|
||||
this.player.setTextOutput(null);
|
||||
this.player.setVideoListener(null);
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.brentvatne.exoplayer;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
@ -10,10 +10,12 @@ import android.os.Message;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.accessibility.CaptioningManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageButton;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import com.brentvatne.react.R;
|
||||
import com.brentvatne.receiver.AudioBecomingNoisyReceiver;
|
||||
@ -25,28 +27,33 @@ import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.modules.timepicker.TimePickerDialogFragment;
|
||||
import com.facebook.react.uimanager.NativeViewHierarchyManager;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.UIBlock;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.DefaultLoadControl;
|
||||
import com.google.android.exoplayer2.DefaultRenderersFactory;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.ExoPlayerFactory;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.metadata.MetadataOutput;
|
||||
import com.google.android.exoplayer2.metadata.MetadataRenderer;
|
||||
import com.google.android.exoplayer2.source.BehindLiveWindowException;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MergingMediaSource;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.source.SingleSampleMediaSource;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.dash.DashMediaSource;
|
||||
import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource;
|
||||
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
|
||||
@ -57,17 +64,20 @@ import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.ui.PlayerControlView;
|
||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultAllocator;
|
||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.android.exoplayer2.ui.PlayerControlView;
|
||||
|
||||
import java.net.CookieHandler;
|
||||
import java.net.CookieManager;
|
||||
import java.net.CookiePolicy;
|
||||
import java.lang.Math;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.lang.Object;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@ -91,6 +101,11 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
DEFAULT_COOKIE_MANAGER.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER);
|
||||
}
|
||||
|
||||
private static Map<Integer, ReactExoplayerView> instances = new HashMap<>();
|
||||
private static int UNIQUE_ID = 0;
|
||||
private int uid = ++UNIQUE_ID;
|
||||
private FullScreenDelegate fullScreenDelegate;
|
||||
|
||||
private final VideoEventEmitter eventEmitter;
|
||||
private final ReactExoplayerConfig config;
|
||||
private final DefaultBandwidthMeter bandwidthMeter;
|
||||
@ -187,7 +202,6 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
createViews();
|
||||
|
||||
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||
themedReactContext.addLifecycleEventListener(this);
|
||||
audioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver(themedReactContext);
|
||||
|
||||
initializePlayer();
|
||||
@ -235,6 +249,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
|
||||
@Override
|
||||
public void onHostResume() {
|
||||
exoPlayerView.setPlayer(player);
|
||||
if (!playInBackground || !isInBackground) {
|
||||
setPlayWhenReady(!isPaused);
|
||||
}
|
||||
@ -275,6 +290,22 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
}
|
||||
|
||||
public static ReactExoplayerView getViewInstance(Integer uid) {
|
||||
return instances.get(uid);
|
||||
}
|
||||
|
||||
public SimpleExoPlayer getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public boolean isPaused() {
|
||||
return isPaused;
|
||||
}
|
||||
|
||||
public void registerFullScreenDelegate(FullScreenDelegate delegate) {
|
||||
this.fullScreenDelegate = delegate;
|
||||
}
|
||||
|
||||
// Internal methods
|
||||
|
||||
/**
|
||||
@ -290,6 +321,15 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
}
|
||||
|
||||
private void showFullscreen() {
|
||||
instances.put(uid, this);
|
||||
Intent intent = new Intent(getContext(), ExoPlayerFullscreenVideoActivity.class);
|
||||
intent.putExtra(ExoPlayerFullscreenVideoActivity.EXTRA_ID, this.uid);
|
||||
boolean isPlaying = player.getPlayWhenReady() && player.getPlaybackState() == Player.STATE_READY;
|
||||
intent.putExtra(ExoPlayerFullscreenVideoActivity.EXTRA_IS_PLAYING, isPlaying);
|
||||
getContext().startActivity(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializing Player control
|
||||
*/
|
||||
@ -302,6 +342,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
playerControlView.setPlayer(player);
|
||||
playerControlView.show();
|
||||
playPauseControlContainer = playerControlView.findViewById(R.id.exo_play_pause_container);
|
||||
playerControlView.findViewById(R.id.exo_fullscreen_button).setOnClickListener(v -> showFullscreen());
|
||||
|
||||
// Invoking onClick event for exoplayerView
|
||||
exoPlayerView.setOnClickListener(new OnClickListener() {
|
||||
@ -374,6 +415,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
|
||||
private void initializePlayer() {
|
||||
themedReactContext.addLifecycleEventListener(this);
|
||||
ReactExoplayerView self = this;
|
||||
// This ensures all props have been settled, to avoid async racing conditions.
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
@ -1217,30 +1259,15 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
return; // Avoid generating events when nothing is changing
|
||||
}
|
||||
isFullscreen = fullscreen;
|
||||
|
||||
Activity activity = themedReactContext.getCurrentActivity();
|
||||
if (activity == null) {
|
||||
return;
|
||||
}
|
||||
Window window = activity.getWindow();
|
||||
View decorView = window.getDecorView();
|
||||
int uiOptions;
|
||||
if (isFullscreen) {
|
||||
if (Util.SDK_INT >= 19) { // 4.4+
|
||||
uiOptions = SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
| SYSTEM_UI_FLAG_FULLSCREEN;
|
||||
} else {
|
||||
uiOptions = SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| SYSTEM_UI_FLAG_FULLSCREEN;
|
||||
}
|
||||
eventEmitter.fullscreenWillPresent();
|
||||
decorView.setSystemUiVisibility(uiOptions);
|
||||
showFullscreen();
|
||||
eventEmitter.fullscreenDidPresent();
|
||||
} else {
|
||||
uiOptions = View.SYSTEM_UI_FLAG_VISIBLE;
|
||||
eventEmitter.fullscreenWillDismiss();
|
||||
decorView.setSystemUiVisibility(uiOptions);
|
||||
if (fullScreenDelegate != null) {
|
||||
fullScreenDelegate.closeFullScreen();
|
||||
}
|
||||
eventEmitter.fullscreenDidDismiss();
|
||||
}
|
||||
}
|
||||
@ -1279,4 +1306,8 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface FullScreenDelegate {
|
||||
void closeFullScreen();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?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"
|
||||
@ -71,6 +72,22 @@
|
||||
android:paddingRight="4dp"
|
||||
android:includeFontPadding="false"
|
||||
android:textColor="#FFBEBEBE"/>
|
||||
</LinearLayout>
|
||||
|
||||
<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="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="center"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="fitCenter"
|
||||
app:srcCompat="@drawable/exo_controls_fullscreen_enter" />
|
||||
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/enclosing_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/black">
|
||||
|
||||
<com.brentvatne.exoplayer.ExoPlayerView
|
||||
android:id="@+id/player_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<com.google.android.exoplayer2.ui.PlayerControlView
|
||||
android:id="@+id/player_controls"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom" />
|
||||
</FrameLayout>
|
@ -1,3 +1,9 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.brentvatne.react">
|
||||
package="com.brentvatne.react">
|
||||
|
||||
<application>
|
||||
<activity
|
||||
android:name="com.brentvatne.exoplayer.ExoPlayerFullscreenVideo"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
Loading…
Reference in New Issue
Block a user