Merge pull request #2688 from react-native-video/revert-2073-feature/android-fullscreen

Revert "[Android] fullscreen video"
This commit is contained in:
Eran Hammer 2022-05-20 22:45:08 -07:00 committed by GitHub
commit 155d94aa06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 41 additions and 271 deletions

View File

@ -535,7 +535,7 @@ Platforms: iOS
* **landscape** * **landscape**
* **portrait** * **portrait**
Platforms: Android ExoPlayer, iOS Platforms: iOS
#### headers #### headers
Pass headers to the HTTP client. Can be used for authorization. Headers must be a part of the source object. Pass headers to the HTTP client. Can be used for authorization. Headers must be a part of the source object.

View File

@ -1,9 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <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.ExoPlayerFullscreenVideoActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:launchMode="singleTop" />
</application>
</manifest> </manifest>

View File

@ -1,155 +0,0 @@
package com.brentvatne.exoplayer;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
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_EXO_PLAYER_VIEW_ID = "extra_id";
public static final String EXTRA_ORIENTATION = "extra_orientation";
private ReactExoplayerView exoplayerView;
private PlayerControlView playerControlView;
private SimpleExoPlayer player;
@Override
public void onCreate(Bundle savedInstanceState) {
int exoplayerViewId = getIntent().getIntExtra(EXTRA_EXO_PLAYER_VIEW_ID, -1);
exoplayerView = ReactExoplayerView.getViewInstance(exoplayerViewId);
if (exoplayerView == null) {
finish();
return;
}
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
String orientation = getIntent().getStringExtra(EXTRA_ORIENTATION);
if ("landscape".equals(orientation)) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
} else if ("portrait".equals(orientation)) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
}
setContentView(R.layout.exo_player_fullscreen_video);
player = exoplayerView.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 -> {
if (exoplayerView != null) {
exoplayerView.setFullscreen(false);
}
});
//Handling the playButton click event
playerControlView.findViewById(R.id.exo_play).setOnClickListener(v -> {
if (player != null && player.getPlaybackState() == Player.STATE_ENDED) {
player.seekTo(0);
}
if (exoplayerView != null) {
exoplayerView.setPausedModifier(false);
}
});
//Handling the pauseButton click event
playerControlView.findViewById(R.id.exo_pause).setOnClickListener(v -> {
if (exoplayerView != null) {
exoplayerView.setPausedModifier(true);
}
});
}
@Override
public void onResume() {
super.onResume();
if (exoplayerView != null) {
exoplayerView.syncPlayerState();
exoplayerView.registerFullScreenDelegate(this);
}
}
@Override
public void onPause() {
super.onPause();
player.setPlayWhenReady(false);
if (exoplayerView != null) {
exoplayerView.registerFullScreenDelegate(null);
}
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
playerControlView.postDelayed(this::hideSystemUI, 200);
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK)) {
if (exoplayerView != null) {
exoplayerView.setFullscreen(false);
return false;
}
return true;
}
return super.onKeyDown(keyCode, event);
}
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();
}
}

View File

@ -129,6 +129,9 @@ public final class ExoPlayerView extends FrameLayout {
* @param player The {@link SimpleExoPlayer} to use. * @param player The {@link SimpleExoPlayer} to use.
*/ */
public void setPlayer(SimpleExoPlayer player) { public void setPlayer(SimpleExoPlayer player) {
if (this.player == player) {
return;
}
if (this.player != null) { if (this.player != null) {
this.player.removeTextOutput(componentListener); this.player.removeTextOutput(componentListener);
this.player.removeVideoListener(componentListener); this.player.removeVideoListener(componentListener);

View File

@ -1,8 +1,8 @@
package com.brentvatne.exoplayer; package com.brentvatne.exoplayer;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.media.AudioManager; import android.media.AudioManager;
import android.net.Uri; import android.net.Uri;
import android.os.Handler; import android.os.Handler;
@ -10,6 +10,7 @@ import android.os.Message;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.Window;
import android.view.accessibility.CaptioningManager; import android.view.accessibility.CaptioningManager;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ImageButton; import android.widget.ImageButton;
@ -29,6 +30,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl; import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.DefaultRenderersFactory; import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
@ -37,6 +39,7 @@ import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager; import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
import com.google.android.exoplayer2.drm.DrmSessionEventListener; import com.google.android.exoplayer2.drm.DrmSessionEventListener;
import com.google.android.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
import com.google.android.exoplayer2.drm.FrameworkMediaDrm; import com.google.android.exoplayer2.drm.FrameworkMediaDrm;
import com.google.android.exoplayer2.drm.HttpMediaDrmCallback; import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
import com.google.android.exoplayer2.drm.UnsupportedDrmException; import com.google.android.exoplayer2.drm.UnsupportedDrmException;
@ -58,8 +61,8 @@ import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource; import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection; import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector; import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.ui.PlayerControlView; import com.google.android.exoplayer2.ui.PlayerControlView;
import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.upstream.BandwidthMeter;
@ -73,10 +76,9 @@ import java.net.CookieHandler;
import java.net.CookieManager; import java.net.CookieManager;
import java.net.CookiePolicy; import java.net.CookiePolicy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.Map;
@SuppressLint("ViewConstructor") @SuppressLint("ViewConstructor")
class ReactExoplayerView extends FrameLayout implements class ReactExoplayerView extends FrameLayout implements
@ -98,9 +100,6 @@ class ReactExoplayerView extends FrameLayout implements
DEFAULT_COOKIE_MANAGER.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER); DEFAULT_COOKIE_MANAGER.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER);
} }
private static Map<Integer, ReactExoplayerView> instances = new HashMap<>();
private FullScreenDelegate fullScreenDelegate;
private final VideoEventEmitter eventEmitter; private final VideoEventEmitter eventEmitter;
private final ReactExoplayerConfig config; private final ReactExoplayerConfig config;
private final DefaultBandwidthMeter bandwidthMeter; private final DefaultBandwidthMeter bandwidthMeter;
@ -119,9 +118,7 @@ class ReactExoplayerView extends FrameLayout implements
private long resumePosition; private long resumePosition;
private boolean loadVideoStarted; private boolean loadVideoStarted;
private boolean isFullscreen; private boolean isFullscreen;
private String fullScreenOrientation;
private boolean isInBackground; private boolean isInBackground;
private boolean isInFullscreen;
private boolean isPaused; private boolean isPaused;
private boolean isBuffering; private boolean isBuffering;
private boolean muted = false; private boolean muted = false;
@ -137,6 +134,8 @@ class ReactExoplayerView extends FrameLayout implements
private int bufferForPlaybackMs = DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS; private int bufferForPlaybackMs = DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS;
private int bufferForPlaybackAfterRebufferMs = DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS; private int bufferForPlaybackAfterRebufferMs = DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS;
private Handler mainHandler;
// Props from React // Props from React
private Uri srcUri; private Uri srcUri;
private String extension; private String extension;
@ -203,6 +202,7 @@ class ReactExoplayerView extends FrameLayout implements
createViews(); createViews();
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
themedReactContext.addLifecycleEventListener(this);
audioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver(themedReactContext); audioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver(themedReactContext);
} }
@ -227,6 +227,8 @@ class ReactExoplayerView extends FrameLayout implements
exoPlayerView.setLayoutParams(layoutParams); exoPlayerView.setLayoutParams(layoutParams);
addView(exoPlayerView, 0, layoutParams); addView(exoPlayerView, 0, layoutParams);
mainHandler = new Handler();
} }
@Override @Override
@ -249,15 +251,7 @@ class ReactExoplayerView extends FrameLayout implements
@Override @Override
public void onHostResume() { public void onHostResume() {
if (!playInBackground || !isInBackground) { if (!playInBackground || !isInBackground) {
if (isInFullscreen) { setPlayWhenReady(!isPaused);
if (player != null) {
exoPlayerView.setPlayer(player);
syncPlayerState();
}
isInFullscreen = false;
} else {
setPlayWhenReady(!isPaused);
}
} }
isInBackground = false; isInBackground = false;
} }
@ -278,7 +272,6 @@ class ReactExoplayerView extends FrameLayout implements
public void cleanUpResources() { public void cleanUpResources() {
stopPlayback(); stopPlayback();
instances.remove(this.getId());
} }
//BandwidthMeter.EventListener implementation //BandwidthMeter.EventListener implementation
@ -297,29 +290,6 @@ class ReactExoplayerView extends FrameLayout implements
} }
} }
public static ReactExoplayerView getViewInstance(Integer uid) {
return instances.get(uid);
}
public SimpleExoPlayer getPlayer() {
return player;
}
public void syncPlayerState() {
if (player == null) return;
if (player.getPlaybackState() == Player.STATE_ENDED) {
// Try to get last frame displayed
player.seekTo(player.getDuration() - 200);
player.setPlayWhenReady(true);
} else {
player.setPlayWhenReady(!isPaused);
}
}
public void registerFullScreenDelegate(FullScreenDelegate delegate) {
this.fullScreenDelegate = delegate;
}
// Internal methods // Internal methods
/** /**
@ -335,15 +305,6 @@ class ReactExoplayerView extends FrameLayout implements
} }
} }
private void showFullscreen() {
instances.put(this.getId(), this);
Intent intent = new Intent(getContext(), ExoPlayerFullscreenVideoActivity.class);
intent.putExtra(ExoPlayerFullscreenVideoActivity.EXTRA_EXO_PLAYER_VIEW_ID, this.getId());
intent.putExtra(ExoPlayerFullscreenVideoActivity.EXTRA_ORIENTATION, this.fullScreenOrientation);
getContext().startActivity(intent);
isInFullscreen = true;
}
/** /**
* Initializing Player control * Initializing Player control
*/ */
@ -356,7 +317,6 @@ class ReactExoplayerView extends FrameLayout implements
playerControlView.setPlayer(player); playerControlView.setPlayer(player);
playerControlView.show(); playerControlView.show();
playPauseControlContainer = playerControlView.findViewById(R.id.exo_play_pause_container); playPauseControlContainer = playerControlView.findViewById(R.id.exo_play_pause_container);
playerControlView.findViewById(R.id.exo_fullscreen_button).setOnClickListener(v -> setFullscreen(true));
// Invoking onClick event for exoplayerView // Invoking onClick event for exoplayerView
exoPlayerView.setOnClickListener(new OnClickListener() { exoPlayerView.setOnClickListener(new OnClickListener() {
@ -429,7 +389,6 @@ class ReactExoplayerView extends FrameLayout implements
} }
private void initializePlayer() { private void initializePlayer() {
themedReactContext.addLifecycleEventListener(this);
ReactExoplayerView self = this; ReactExoplayerView self = this;
// This ensures all props have been settled, to avoid async racing conditions. // This ensures all props have been settled, to avoid async racing conditions.
new Handler().postDelayed(new Runnable() { new Handler().postDelayed(new Runnable() {
@ -452,7 +411,7 @@ class ReactExoplayerView extends FrameLayout implements
new DefaultRenderersFactory(getContext()) new DefaultRenderersFactory(getContext())
.setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF); .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF);
player = new SimpleExoPlayer.Builder(getContext(), renderersFactory) player = new SimpleExoPlayer.Builder(getContext(), renderersFactory)
.setTrackSelector(trackSelector) .setTrackSelector(trackSelector)
.setBandwidthMeter(bandwidthMeter) .setBandwidthMeter(bandwidthMeter)
.setLoadControl(defaultLoadControl) .setLoadControl(defaultLoadControl)
.build(); .build();
@ -682,6 +641,9 @@ class ReactExoplayerView extends FrameLayout implements
} }
private void onStopPlayback() { private void onStopPlayback() {
if (isFullscreen) {
setFullscreen(false);
}
audioManager.abandonAudioFocus(this); audioManager.abandonAudioFocus(this);
} }
@ -1336,23 +1298,34 @@ class ReactExoplayerView extends FrameLayout implements
return; // Avoid generating events when nothing is changing return; // Avoid generating events when nothing is changing
} }
isFullscreen = fullscreen; isFullscreen = fullscreen;
Activity activity = themedReactContext.getCurrentActivity();
if (activity == null) {
return;
}
Window window = activity.getWindow();
View decorView = window.getDecorView();
int uiOptions;
if (isFullscreen) { 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(); eventEmitter.fullscreenWillPresent();
showFullscreen(); decorView.setSystemUiVisibility(uiOptions);
eventEmitter.fullscreenDidPresent(); eventEmitter.fullscreenDidPresent();
} else { } else {
uiOptions = View.SYSTEM_UI_FLAG_VISIBLE;
eventEmitter.fullscreenWillDismiss(); eventEmitter.fullscreenWillDismiss();
if (fullScreenDelegate != null) { decorView.setSystemUiVisibility(uiOptions);
fullScreenDelegate.closeFullScreen();
}
eventEmitter.fullscreenDidDismiss(); eventEmitter.fullscreenDidDismiss();
} }
} }
public void setFullscreenOrientation(String orientation) {
this.fullScreenOrientation = orientation;
}
public void setUseTextureView(boolean useTextureView) { public void setUseTextureView(boolean useTextureView) {
boolean finallyUseTextureView = useTextureView && this.drmUUID == null; boolean finallyUseTextureView = useTextureView && this.drmUUID == null;
exoPlayerView.setUseTextureView(finallyUseTextureView); exoPlayerView.setUseTextureView(finallyUseTextureView);
@ -1422,8 +1395,4 @@ class ReactExoplayerView extends FrameLayout implements
} }
} }
} }
public interface FullScreenDelegate {
void closeFullScreen();
}
} }

View File

@ -64,7 +64,6 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
private static final String PROP_PLAY_IN_BACKGROUND = "playInBackground"; private static final String PROP_PLAY_IN_BACKGROUND = "playInBackground";
private static final String PROP_DISABLE_FOCUS = "disableFocus"; private static final String PROP_DISABLE_FOCUS = "disableFocus";
private static final String PROP_FULLSCREEN = "fullscreen"; private static final String PROP_FULLSCREEN = "fullscreen";
private static final String PROP_FULLSCREEN_ORIENTATION = "fullscreenOrientation";
private static final String PROP_USE_TEXTURE_VIEW = "useTextureView"; private static final String PROP_USE_TEXTURE_VIEW = "useTextureView";
private static final String PROP_SELECTED_VIDEO_TRACK = "selectedVideoTrack"; private static final String PROP_SELECTED_VIDEO_TRACK = "selectedVideoTrack";
private static final String PROP_SELECTED_VIDEO_TRACK_TYPE = "type"; private static final String PROP_SELECTED_VIDEO_TRACK_TYPE = "type";
@ -300,11 +299,6 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
videoView.setFullscreen(fullscreen); videoView.setFullscreen(fullscreen);
} }
@ReactProp(name = PROP_FULLSCREEN_ORIENTATION)
public void setFullscreenOrientation(final ReactExoplayerView videoView, final String fullscreenOrientation) {
videoView.setFullscreenOrientation(fullscreenOrientation);
}
@ReactProp(name = PROP_USE_TEXTURE_VIEW, defaultBoolean = true) @ReactProp(name = PROP_USE_TEXTURE_VIEW, defaultBoolean = true)
public void setUseTextureView(final ReactExoplayerView videoView, final boolean useTextureView) { public void setUseTextureView(final ReactExoplayerView videoView, final boolean useTextureView) {
videoView.setUseTextureView(useTextureView); videoView.setUseTextureView(useTextureView);

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <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_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom" android:layout_gravity="bottom"
@ -72,22 +71,6 @@
android:paddingRight="4dp" android:paddingRight="4dp"
android:includeFontPadding="false" android:includeFontPadding="false"
android:textColor="#FFBEBEBE"/> android:textColor="#FFBEBEBE"/>
<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>
</LinearLayout> </LinearLayout>

View File

@ -1,18 +0,0 @@
<?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>

View File

@ -1,3 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.brentvatne.react"> package="com.brentvatne.react">
</manifest> </manifest>