Merge branch 'master' into master
This commit is contained in:
@@ -12,9 +12,9 @@ android {
|
||||
|
||||
dependencies {
|
||||
provided 'com.facebook.react:react-native:+'
|
||||
compile 'com.google.android.exoplayer:exoplayer:r2.4.0'
|
||||
compile('com.google.android.exoplayer:extension-okhttp:r2.4.0') {
|
||||
compile 'com.google.android.exoplayer:exoplayer:2.7.3'
|
||||
compile('com.google.android.exoplayer:extension-okhttp:2.7.3') {
|
||||
exclude group: 'com.squareup.okhttp3', module: 'okhttp'
|
||||
}
|
||||
compile 'com.squareup.okhttp3:okhttp:3.4.2'
|
||||
compile 'com.squareup.okhttp3:okhttp:3.9.1'
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.ui.SubtitleView;
|
||||
|
||||
import java.util.List;
|
||||
import java.lang.Object;
|
||||
|
||||
@TargetApi(16)
|
||||
public final class ExoPlayerView extends FrameLayout {
|
||||
@@ -212,12 +213,12 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPositionDiscontinuity() {
|
||||
public void onPositionDiscontinuity(int reason) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimelineChanged(Timeline timeline, Object manifest) {
|
||||
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@@ -235,6 +236,21 @@ public final class ExoPlayerView extends FrameLayout {
|
||||
public void onMetadata(Metadata metadata) {
|
||||
Log.d("onMetadata", "onMetadata");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSeekProcessed() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRepeatModeChanged(int repeatMode) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package com.brentvatne.exoplayer;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.net.Uri;
|
||||
@@ -8,6 +9,8 @@ import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.brentvatne.react.R;
|
||||
@@ -23,6 +26,7 @@ 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;
|
||||
@@ -54,6 +58,7 @@ import java.net.CookieManager;
|
||||
import java.net.CookiePolicy;
|
||||
import java.lang.Math;
|
||||
import java.util.Map;
|
||||
import java.lang.Object;
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
class ReactExoplayerView extends FrameLayout implements
|
||||
@@ -87,6 +92,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
private int resumeWindow;
|
||||
private long resumePosition;
|
||||
private boolean loadVideoStarted;
|
||||
private boolean isFullscreen;
|
||||
private boolean isPaused = true;
|
||||
private boolean isBuffering;
|
||||
private float rate = 1f;
|
||||
@@ -116,7 +122,8 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
&& player.getPlayWhenReady()
|
||||
) {
|
||||
long pos = player.getCurrentPosition();
|
||||
eventEmitter.progressChanged(pos, player.getBufferedPercentage());
|
||||
long bufferedDuration = player.getBufferedPercentage() * player.getDuration();
|
||||
eventEmitter.progressChanged(pos, bufferedDuration, player.getDuration());
|
||||
msg = obtainMessage(SHOW_PROGRESS);
|
||||
sendMessageDelayed(msg, Math.round(mProgressUpdateInterval));
|
||||
}
|
||||
@@ -333,6 +340,9 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
|
||||
private void onStopPlayback() {
|
||||
if (isFullscreen) {
|
||||
setFullscreen(false);
|
||||
}
|
||||
setKeepScreenOn(false);
|
||||
audioManager.abandonAudioFocus(this);
|
||||
}
|
||||
@@ -458,17 +468,38 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPositionDiscontinuity() {
|
||||
public void onPositionDiscontinuity(int reason) {
|
||||
if (playerNeedsSource) {
|
||||
// This will only occur if the user has performed a seek whilst in the error state. Update the
|
||||
// resume position so that if the user then retries, playback will resume from the position to
|
||||
// which they seeked.
|
||||
updateResumePosition();
|
||||
}
|
||||
// When repeat is turned on, reaching the end of the video will not cause a state change
|
||||
// so we need to explicitly detect it.
|
||||
if (reason == ExoPlayer.DISCONTINUITY_REASON_PERIOD_TRANSITION
|
||||
&& player.getRepeatMode() == Player.REPEAT_MODE_ONE) {
|
||||
eventEmitter.end();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimelineChanged(Timeline timeline, Object manifest) {
|
||||
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSeekProcessed() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRepeatModeChanged(int repeatMode) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@@ -485,6 +516,7 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
@Override
|
||||
public void onPlayerError(ExoPlaybackException e) {
|
||||
String errorString = null;
|
||||
Exception ex = e;
|
||||
if (e.type == ExoPlaybackException.TYPE_RENDERER) {
|
||||
Exception cause = e.getRendererException();
|
||||
if (cause instanceof MediaCodecRenderer.DecoderInitializationException) {
|
||||
@@ -507,8 +539,12 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (e.type == ExoPlaybackException.TYPE_SOURCE) {
|
||||
ex = e.getSourceException();
|
||||
errorString = getResources().getString(R.string.unrecognized_media_format);
|
||||
}
|
||||
if (errorString != null) {
|
||||
eventEmitter.error(errorString, e);
|
||||
eventEmitter.error(errorString, ex);
|
||||
}
|
||||
playerNeedsSource = true;
|
||||
if (isBehindLiveWindow(e)) {
|
||||
@@ -585,6 +621,13 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
}
|
||||
|
||||
public void setRepeatModifier(boolean repeat) {
|
||||
if (player != null) {
|
||||
if (repeat) {
|
||||
player.setRepeatMode(Player.REPEAT_MODE_ONE);
|
||||
} else {
|
||||
player.setRepeatMode(Player.REPEAT_MODE_OFF);
|
||||
}
|
||||
}
|
||||
this.repeat = repeat;
|
||||
}
|
||||
|
||||
@@ -636,4 +679,37 @@ class ReactExoplayerView extends FrameLayout implements
|
||||
public void setDisableFocus(boolean disableFocus) {
|
||||
this.disableFocus = disableFocus;
|
||||
}
|
||||
|
||||
public void setFullscreen(boolean fullscreen) {
|
||||
if (fullscreen == isFullscreen) {
|
||||
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);
|
||||
eventEmitter.fullscreenDidPresent();
|
||||
} else {
|
||||
uiOptions = View.SYSTEM_UI_FLAG_VISIBLE;
|
||||
eventEmitter.fullscreenWillDismiss();
|
||||
decorView.setSystemUiVisibility(uiOptions);
|
||||
eventEmitter.fullscreenDidDismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -34,6 +34,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
private static final String PROP_RATE = "rate";
|
||||
private static final String PROP_PLAY_IN_BACKGROUND = "playInBackground";
|
||||
private static final String PROP_DISABLE_FOCUS = "disableFocus";
|
||||
private static final String PROP_FULLSCREEN = "fullscreen";
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
@@ -159,6 +160,11 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
videoView.setDisableFocus(disableFocus);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_FULLSCREEN, defaultBoolean = false)
|
||||
public void setFullscreen(final ReactExoplayerView videoView, final boolean fullscreen) {
|
||||
videoView.setFullscreen(fullscreen);
|
||||
}
|
||||
|
||||
private boolean startsWithValidScheme(String uriString) {
|
||||
return uriString.startsWith("http://")
|
||||
|| uriString.startsWith("https://")
|
||||
|
@@ -31,6 +31,11 @@ class VideoEventEmitter {
|
||||
private static final String EVENT_PROGRESS = "onVideoProgress";
|
||||
private static final String EVENT_SEEK = "onVideoSeek";
|
||||
private static final String EVENT_END = "onVideoEnd";
|
||||
private static final String EVENT_FULLSCREEN_WILL_PRESENT = "onVideoFullscreenPlayerWillPresent";
|
||||
private static final String EVENT_FULLSCREEN_DID_PRESENT = "onVideoFullscreenPlayerDidPresent";
|
||||
private static final String EVENT_FULLSCREEN_WILL_DISMISS = "onVideoFullscreenPlayerWillDismiss";
|
||||
private static final String EVENT_FULLSCREEN_DID_DISMISS = "onVideoFullscreenPlayerDidDismiss";
|
||||
|
||||
private static final String EVENT_STALLED = "onPlaybackStalled";
|
||||
private static final String EVENT_RESUME = "onPlaybackResume";
|
||||
private static final String EVENT_READY = "onReadyForDisplay";
|
||||
@@ -48,6 +53,10 @@ class VideoEventEmitter {
|
||||
EVENT_PROGRESS,
|
||||
EVENT_SEEK,
|
||||
EVENT_END,
|
||||
EVENT_FULLSCREEN_WILL_PRESENT,
|
||||
EVENT_FULLSCREEN_DID_PRESENT,
|
||||
EVENT_FULLSCREEN_WILL_DISMISS,
|
||||
EVENT_FULLSCREEN_DID_DISMISS,
|
||||
EVENT_STALLED,
|
||||
EVENT_RESUME,
|
||||
EVENT_READY,
|
||||
@@ -67,6 +76,10 @@ class VideoEventEmitter {
|
||||
EVENT_PROGRESS,
|
||||
EVENT_SEEK,
|
||||
EVENT_END,
|
||||
EVENT_FULLSCREEN_WILL_PRESENT,
|
||||
EVENT_FULLSCREEN_DID_PRESENT,
|
||||
EVENT_FULLSCREEN_WILL_DISMISS,
|
||||
EVENT_FULLSCREEN_DID_DISMISS,
|
||||
EVENT_STALLED,
|
||||
EVENT_RESUME,
|
||||
EVENT_READY,
|
||||
@@ -89,6 +102,7 @@ class VideoEventEmitter {
|
||||
|
||||
private static final String EVENT_PROP_DURATION = "duration";
|
||||
private static final String EVENT_PROP_PLAYABLE_DURATION = "playableDuration";
|
||||
private static final String EVENT_PROP_SEEKABLE_DURATION = "seekableDuration";
|
||||
private static final String EVENT_PROP_CURRENT_TIME = "currentTime";
|
||||
private static final String EVENT_PROP_SEEK_TIME = "seekTime";
|
||||
private static final String EVENT_PROP_NATURAL_SIZE = "naturalSize";
|
||||
@@ -141,10 +155,11 @@ class VideoEventEmitter {
|
||||
receiveEvent(EVENT_LOAD, event);
|
||||
}
|
||||
|
||||
void progressChanged(double currentPosition, double bufferedDuration) {
|
||||
void progressChanged(double currentPosition, double bufferedDuration, double seekableDuration) {
|
||||
WritableMap event = Arguments.createMap();
|
||||
event.putDouble(EVENT_PROP_CURRENT_TIME, currentPosition / 1000D);
|
||||
event.putDouble(EVENT_PROP_PLAYABLE_DURATION, bufferedDuration / 1000D);
|
||||
event.putDouble(EVENT_PROP_SEEKABLE_DURATION, seekableDuration / 1000D);
|
||||
receiveEvent(EVENT_PROGRESS, event);
|
||||
}
|
||||
|
||||
@@ -173,6 +188,22 @@ class VideoEventEmitter {
|
||||
receiveEvent(EVENT_END, null);
|
||||
}
|
||||
|
||||
void fullscreenWillPresent() {
|
||||
receiveEvent(EVENT_FULLSCREEN_WILL_PRESENT, null);
|
||||
}
|
||||
|
||||
void fullscreenDidPresent() {
|
||||
receiveEvent(EVENT_FULLSCREEN_DID_PRESENT, null);
|
||||
}
|
||||
|
||||
void fullscreenWillDismiss() {
|
||||
receiveEvent(EVENT_FULLSCREEN_WILL_DISMISS, null);
|
||||
}
|
||||
|
||||
void fullscreenDidDismiss() {
|
||||
receiveEvent(EVENT_FULLSCREEN_DID_DISMISS, null);
|
||||
}
|
||||
|
||||
void error(String errorString, Exception exception) {
|
||||
WritableMap error = Arguments.createMap();
|
||||
error.putString(EVENT_PROP_ERROR_STRING, errorString);
|
||||
|
@@ -9,4 +9,6 @@
|
||||
|
||||
<string name="error_instantiating_decoder">Unable to instantiate decoder <xliff:g id="decoder_name">%1$s</xliff:g></string>
|
||||
|
||||
<string name="unrecognized_media_format">Unrecognized media format</string>
|
||||
|
||||
</resources>
|
||||
|
Reference in New Issue
Block a user