Skip to content

Commit e0fd69e

Browse files
authored
Merge pull request #1414 from IbrahimSulai/master
Support for displaying controls in Android Exoplayer
2 parents 80391d4 + 4080349 commit e0fd69e

File tree

4 files changed

+178
-2
lines changed

4 files changed

+178
-2
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -359,9 +359,9 @@ Determines whether to show player controls.
359359

360360
Note on iOS, controls are always shown when in fullscreen mode.
361361

362-
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).
362+
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).
363363

364-
Platforms: iOS, react-native-dom
364+
Platforms: Android ExoPlayer, iOS, react-native-dom
365365

366366
#### filter
367367
Add video filter

android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java

+94
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
6565
import com.google.android.exoplayer2.util.MimeTypes;
6666
import com.google.android.exoplayer2.util.Util;
67+
import com.google.android.exoplayer2.ui.PlayerControlView;
6768

6869
import java.net.CookieHandler;
6970
import java.net.CookieManager;
@@ -96,6 +97,9 @@ class ReactExoplayerView extends FrameLayout implements
9697
}
9798

9899
private final VideoEventEmitter eventEmitter;
100+
private PlayerControlView playerControlView;
101+
private View playPauseControlContainer;
102+
private Player.EventListener eventListener;
99103

100104
private Handler mainHandler;
101105
private ExoPlayerView exoPlayerView;
@@ -257,6 +261,76 @@ public void onBandwidthSample(int elapsedMs, long bytes, long bitrate) {
257261
}
258262

259263
// Internal methods
264+
265+
/**
266+
* Toggling the visibility of the player control view
267+
*/
268+
private void togglePlayerControlVisibility() {
269+
reLayout(playerControlView);
270+
if (playerControlView.isVisible()) {
271+
playerControlView.hide();
272+
} else {
273+
playerControlView.show();
274+
}
275+
}
276+
277+
/**
278+
* Initializing Player control
279+
*/
280+
private void initializePlayerControl() {
281+
if (playerControlView == null) {
282+
playerControlView = new PlayerControlView(getContext());
283+
}
284+
285+
// Setting the player for the playerControlView
286+
playerControlView.setPlayer(player);
287+
playerControlView.show();
288+
playPauseControlContainer = playerControlView.findViewById(R.id.exo_play_pause_container);
289+
290+
// Invoking onClick event for exoplayerView
291+
exoPlayerView.setOnClickListener(new OnClickListener() {
292+
@Override
293+
public void onClick(View v) {
294+
togglePlayerControlVisibility();
295+
}
296+
});
297+
298+
// Invoking onPlayerStateChanged event for Player
299+
eventListener = new Player.EventListener() {
300+
@Override
301+
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
302+
reLayout(playPauseControlContainer);
303+
//Remove this eventListener once its executed. since UI will work fine once after the reLayout is done
304+
player.removeListener(eventListener);
305+
}
306+
};
307+
player.addListener(eventListener);
308+
}
309+
310+
/**
311+
* Adding Player control to the frame layout
312+
*/
313+
private void addPlayerControl() {
314+
LayoutParams layoutParams = new LayoutParams(
315+
LayoutParams.MATCH_PARENT,
316+
LayoutParams.MATCH_PARENT);
317+
playerControlView.setLayoutParams(layoutParams);
318+
addView(playerControlView, 1, layoutParams);
319+
}
320+
321+
/**
322+
* Update the layout
323+
* @param view view needs to update layout
324+
*
325+
* This is a workaround for the open bug in react-native: https://github.com/facebook/react-native/issues/17968
326+
*/
327+
private void reLayout(View view) {
328+
if (view == null) return;
329+
view.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
330+
MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
331+
view.layout(view.getLeft(), view.getTop(), view.getMeasuredWidth(), view.getMeasuredHeight());
332+
}
333+
260334
private void initializePlayer() {
261335
if (player == null) {
262336
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(BANDWIDTH_METER);
@@ -302,6 +376,9 @@ private void initializePlayer() {
302376
eventEmitter.loadStart();
303377
loadVideoStarted = true;
304378
}
379+
380+
// Initializing the playerControlView
381+
initializePlayerControl();
305382
}
306383

307384
private MediaSource buildMediaSource(Uri uri, String overrideExtension) {
@@ -517,6 +594,10 @@ public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
517594
onBuffering(false);
518595
startProgressHandler();
519596
videoLoaded();
597+
//Setting the visibility for the playerControlView
598+
if(playerControlView != null) {
599+
playerControlView.show();
600+
}
520601
break;
521602
case ExoPlayer.STATE_ENDED:
522603
text += "ended";
@@ -1056,4 +1137,17 @@ public void setBufferConfig(int newMinBufferMs, int newMaxBufferMs, int newBuffe
10561137
releasePlayer();
10571138
initializePlayer();
10581139
}
1140+
1141+
/**
1142+
* Handling controls prop
1143+
*
1144+
* @param controls Controls prop, if true enable controls, if false disable them
1145+
*/
1146+
public void setControls(boolean controls) {
1147+
if (controls && exoPlayerView != null) {
1148+
addPlayerControl();
1149+
} else if (getChildAt(1) instanceof PlayerControlView && exoPlayerView != null) {
1150+
removeViewAt(1);
1151+
}
1152+
}
10591153
}

android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java

+6
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
5757
private static final String PROP_SELECTED_VIDEO_TRACK_TYPE = "type";
5858
private static final String PROP_SELECTED_VIDEO_TRACK_VALUE = "value";
5959
private static final String PROP_HIDE_SHUTTER_VIEW = "hideShutterView";
60+
private static final String PROP_CONTROLS = "controls";
6061

6162
@Override
6263
public String getName() {
@@ -255,6 +256,11 @@ public void setHideShutterView(final ReactExoplayerView videoView, final boolean
255256
videoView.setHideShutterView(hideShutterView);
256257
}
257258

259+
@ReactProp(name = PROP_CONTROLS, defaultBoolean = false)
260+
public void setControls(final ReactExoplayerView videoView, final boolean controls) {
261+
videoView.setControls(controls);
262+
}
263+
258264
@ReactProp(name = PROP_BUFFER_CONFIG)
259265
public void setBufferConfig(final ReactExoplayerView videoView, @Nullable ReadableMap bufferConfig) {
260266
int minBufferMs = DefaultLoadControl.DEFAULT_MIN_BUFFER_MS;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:layout_width="match_parent"
4+
android:layout_height="wrap_content"
5+
android:layout_gravity="bottom"
6+
android:layoutDirection="ltr"
7+
android:background="#CC000000"
8+
android:orientation="vertical">
9+
10+
<LinearLayout
11+
android:layout_width="match_parent"
12+
android:layout_height="wrap_content"
13+
android:gravity="center"
14+
android:paddingTop="4dp"
15+
android:orientation="horizontal">
16+
17+
<ImageButton android:id="@id/exo_prev"
18+
style="@style/ExoMediaButton.Previous"/>
19+
20+
<ImageButton android:id="@id/exo_rew"
21+
style="@style/ExoMediaButton.Rewind"/>
22+
<FrameLayout
23+
android:id="@+id/exo_play_pause_container"
24+
android:layout_width="wrap_content"
25+
android:layout_height="wrap_content"
26+
android:layout_gravity="center">
27+
<ImageButton android:id="@id/exo_play"
28+
style="@style/ExoMediaButton.Play"/>
29+
30+
<ImageButton android:id="@id/exo_pause"
31+
style="@style/ExoMediaButton.Pause"/>
32+
</FrameLayout>
33+
34+
<ImageButton android:id="@id/exo_ffwd"
35+
style="@style/ExoMediaButton.FastForward"/>
36+
37+
<ImageButton android:id="@id/exo_next"
38+
style="@style/ExoMediaButton.Next"/>
39+
40+
</LinearLayout>
41+
42+
<LinearLayout
43+
android:layout_width="match_parent"
44+
android:layout_height="wrap_content"
45+
android:layout_marginTop="4dp"
46+
android:gravity="center_vertical"
47+
android:orientation="horizontal">
48+
49+
<TextView android:id="@id/exo_position"
50+
android:layout_width="50dp"
51+
android:layout_height="wrap_content"
52+
android:textSize="14sp"
53+
android:textStyle="bold"
54+
android:paddingLeft="4dp"
55+
android:paddingRight="4dp"
56+
android:includeFontPadding="false"
57+
android:textColor="#FFBEBEBE"/>
58+
59+
<com.google.android.exoplayer2.ui.DefaultTimeBar
60+
android:id="@id/exo_progress"
61+
android:layout_width="0dp"
62+
android:layout_weight="1"
63+
android:layout_height="26dp"/>
64+
65+
<TextView android:id="@id/exo_duration"
66+
android:layout_width="50dp"
67+
android:layout_height="wrap_content"
68+
android:textSize="14sp"
69+
android:textStyle="bold"
70+
android:paddingLeft="4dp"
71+
android:paddingRight="4dp"
72+
android:includeFontPadding="false"
73+
android:textColor="#FFBEBEBE"/>
74+
</LinearLayout>
75+
76+
</LinearLayout>

0 commit comments

Comments
 (0)