diff --git a/README.md b/README.md index 8af2d371..a8a6b4c5 100644 --- a/README.md +++ b/README.md @@ -359,9 +359,9 @@ Determines whether to show player controls. Note on iOS, controls are always shown when in fullscreen mode. -Controls are not available Android because the system does not provide a stock set of controls. You will need to build your own or use a package like [react-native-video-controls](https://github.com/itsnubix/react-native-video-controls) or [react-native-video-player](https://github.com/cornedor/react-native-video-player). +For Android MediaPlayer, you will need to build your own controls or use a package like [react-native-video-controls](https://github.com/itsnubix/react-native-video-controls) or [react-native-video-player](https://github.com/cornedor/react-native-video-player). -Platforms: iOS, react-native-dom +Platforms: Android ExoPlayer, iOS, react-native-dom #### filter Add video filter diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 64c8a404..2ecd605e 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -64,6 +64,7 @@ import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; +import com.google.android.exoplayer2.ui.PlayerControlView; import java.net.CookieHandler; import java.net.CookieManager; @@ -96,6 +97,9 @@ class ReactExoplayerView extends FrameLayout implements } private final VideoEventEmitter eventEmitter; + private PlayerControlView playerControlView; + private View playPauseControlContainer; + private Player.EventListener eventListener; private Handler mainHandler; private ExoPlayerView exoPlayerView; @@ -257,6 +261,76 @@ class ReactExoplayerView extends FrameLayout implements } // Internal methods + + /** + * Toggling the visibility of the player control view + */ + private void togglePlayerControlVisibility() { + reLayout(playerControlView); + if (playerControlView.isVisible()) { + playerControlView.hide(); + } else { + playerControlView.show(); + } + } + + /** + * Initializing Player control + */ + private void initializePlayerControl() { + if (playerControlView == null) { + playerControlView = new PlayerControlView(getContext()); + } + + // Setting the player for the playerControlView + playerControlView.setPlayer(player); + playerControlView.show(); + playPauseControlContainer = playerControlView.findViewById(R.id.exo_play_pause_container); + + // Invoking onClick event for exoplayerView + exoPlayerView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + togglePlayerControlVisibility(); + } + }); + + // Invoking onPlayerStateChanged event for Player + eventListener = new Player.EventListener() { + @Override + public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { + reLayout(playPauseControlContainer); + //Remove this eventListener once its executed. since UI will work fine once after the reLayout is done + player.removeListener(eventListener); + } + }; + player.addListener(eventListener); + } + + /** + * Adding Player control to the frame layout + */ + private void addPlayerControl() { + LayoutParams layoutParams = new LayoutParams( + LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT); + playerControlView.setLayoutParams(layoutParams); + addView(playerControlView, 1, layoutParams); + } + + /** + * Update the layout + * @param view view needs to update layout + * + * This is a workaround for the open bug in react-native: https://github.com/facebook/react-native/issues/17968 + */ + private void reLayout(View view) { + if (view == null) return; + view.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY)); + view.layout(view.getLeft(), view.getTop(), view.getMeasuredWidth(), view.getMeasuredHeight()); + } + private void initializePlayer() { if (player == null) { TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(BANDWIDTH_METER); @@ -302,6 +376,9 @@ class ReactExoplayerView extends FrameLayout implements eventEmitter.loadStart(); loadVideoStarted = true; } + + // Initializing the playerControlView + initializePlayerControl(); } private MediaSource buildMediaSource(Uri uri, String overrideExtension) { @@ -517,6 +594,10 @@ class ReactExoplayerView extends FrameLayout implements onBuffering(false); startProgressHandler(); videoLoaded(); + //Setting the visibility for the playerControlView + if(playerControlView != null) { + playerControlView.show(); + } break; case ExoPlayer.STATE_ENDED: text += "ended"; @@ -1056,4 +1137,17 @@ class ReactExoplayerView extends FrameLayout implements releasePlayer(); initializePlayer(); } + + /** + * Handling controls prop + * + * @param controls Controls prop, if true enable controls, if false disable them + */ + public void setControls(boolean controls) { + if (controls && exoPlayerView != null) { + addPlayerControl(); + } else if (getChildAt(1) instanceof PlayerControlView && exoPlayerView != null) { + removeViewAt(1); + } + } } diff --git a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java index 31bd8e08..b3c6ad12 100644 --- a/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -57,6 +57,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager + + + + + + + + + + + + + + + + + + + + + + + + + + + + +