diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoView.java b/android/src/main/java/com/brentvatne/react/ReactVideoView.java index 479cc601..4fd688f4 100644 --- a/android/src/main/java/com/brentvatne/react/ReactVideoView.java +++ b/android/src/main/java/com/brentvatne/react/ReactVideoView.java @@ -1,6 +1,5 @@ package com.brentvatne.react; -import android.content.Context; import android.media.MediaPlayer; import android.os.Handler; import com.facebook.react.bridge.Arguments; @@ -10,9 +9,31 @@ import com.facebook.react.uimanager.events.RCTEventEmitter; import com.yqritc.scalablevideoview.ScalableType; import com.yqritc.scalablevideoview.ScalableVideoView; -public class ReactVideoView extends ScalableVideoView { +public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnPreparedListener, MediaPlayer + .OnErrorListener, MediaPlayer.OnCompletionListener { + + public enum Events { + EVENT_LOAD_START("onVideoLoadStart"), + EVENT_LOAD("onVideoLoad"), + EVENT_ERROR("onVideoError"), + EVENT_PROGRESS("onVideoProgress"), + EVENT_SEEK("onVideoSeek"), + EVENT_END("onVideoEnd"); + + private final String mName; + + Events(final String name) { + mName = name; + } + + @Override + public String toString() { + return mName; + } + } private ThemedReactContext mThemedReactContext; + private RCTEventEmitter mEventEmitter; private Handler mProgressUpdateHandler = new Handler(); private Runnable mProgressUpdateRunnable = null; @@ -27,22 +48,26 @@ public class ReactVideoView extends ScalableVideoView { super(themedReactContext); mThemedReactContext = themedReactContext; + mEventEmitter = themedReactContext.getJSModule(RCTEventEmitter.class); - mMediaPlayer = new MediaPlayer(); - mMediaPlayer.setOnVideoSizeChangedListener(this); + initializeMediaPlayerIfNeeded(); setSurfaceTextureListener(this); + final MediaPlayer mediaPlayer = mMediaPlayer; + mProgressUpdateRunnable = new Runnable() { @Override public void run() { - final RCTEventEmitter eventEmitter = getEventEmitter(); - if (mMediaPlayer.isPlaying()) { + try { WritableMap event = Arguments.createMap(); // TODO: Other event properties. - event.putDouble("currentTime", (double) mMediaPlayer.getCurrentPosition() / (double) 1000); - event.putDouble("duration", (double) mMediaPlayer.getDuration() / (double) 1000); - eventEmitter.receiveEvent(getId(), ReactVideoViewManager.EVENT_PROGRESS, event); + event.putDouble("currentTime", (double) mediaPlayer.getCurrentPosition() / (double) 1000); + event.putDouble("duration", (double) mediaPlayer.getDuration() / (double) 1000); + event.putDouble("playableDuration", (double) mediaPlayer.getDuration() / (double) 1000); + mEventEmitter.receiveEvent(getId(), Events.EVENT_PROGRESS.toString(), event); + } catch (Exception e) { + // Do nothing. } mProgressUpdateHandler.postDelayed(mProgressUpdateRunnable, 250); } @@ -50,8 +75,14 @@ public class ReactVideoView extends ScalableVideoView { mProgressUpdateHandler.post(mProgressUpdateRunnable); } - private RCTEventEmitter getEventEmitter() { - return mThemedReactContext.getJSModule(RCTEventEmitter.class); + private void initializeMediaPlayerIfNeeded() { + if (mMediaPlayer == null) { + mMediaPlayer = new MediaPlayer(); + mMediaPlayer.setScreenOnWhilePlaying(true); + mMediaPlayer.setOnVideoSizeChangedListener(this); + mMediaPlayer.setOnErrorListener(this); + mMediaPlayer.setOnPreparedListener(this); + } } public void reset() { @@ -60,12 +91,14 @@ public class ReactVideoView extends ScalableVideoView { public void setResizeModeModifier(final ScalableType resizeMode) { mResizeMode = resizeMode; + initializeMediaPlayerIfNeeded(); setScalableType(resizeMode); invalidate(); } public void setRepeatModifier(final boolean repeat) { mRepeat = repeat; + initializeMediaPlayerIfNeeded(); setLooping(repeat); } @@ -73,6 +106,8 @@ public class ReactVideoView extends ScalableVideoView { mPaused = paused; try { + initializeMediaPlayerIfNeeded(); + if (!mPaused) { start(); } else { @@ -86,6 +121,8 @@ public class ReactVideoView extends ScalableVideoView { public void setMutedModifier(final boolean muted) { mMuted = muted; + initializeMediaPlayerIfNeeded(); + if (mMuted) { setVolume(0, 0); } else { @@ -95,6 +132,7 @@ public class ReactVideoView extends ScalableVideoView { public void setVolumeModifier(final float volume) { mVolume = volume; + initializeMediaPlayerIfNeeded(); setMutedModifier(mMuted); } @@ -104,4 +142,41 @@ public class ReactVideoView extends ScalableVideoView { setPausedModifier(mPaused); setVolumeModifier(mVolume); } + + @Override + public void onPrepared(MediaPlayer mp) { + WritableMap event = Arguments.createMap(); + event.putDouble("duration", (double) mp.getDuration() / (double) 1000); + event.putDouble("currentTime", (double) mp.getCurrentPosition() / (double) 1000); + // TODO: Add canX properties. + mEventEmitter.receiveEvent(getId(), Events.EVENT_LOAD.toString(), event); + + applyModifiers(); + } + + @Override + public boolean onError(MediaPlayer mp, int what, int extra) { + WritableMap error = Arguments.createMap(); + error.putInt("what", what); + error.putInt("extra", extra); + WritableMap event = Arguments.createMap(); + event.putMap("error", error); + mEventEmitter.receiveEvent(getId(), Events.EVENT_ERROR.toString(), event); + return true; + } + + @Override + public void seekTo(int msec) { + WritableMap event = Arguments.createMap(); + event.putDouble("currentTime", (double) getCurrentPosition() / (double) 1000); + event.putDouble("seekTime", (double) msec / (double) 1000); + mEventEmitter.receiveEvent(getId(), Events.EVENT_SEEK.toString(), event); + + super.seekTo(msec); + } + + @Override + public void onCompletion(MediaPlayer mp) { + mEventEmitter.receiveEvent(getId(), Events.EVENT_END.toString(), null); + } } diff --git a/android/src/main/java/com/brentvatne/react/ReactVideoViewManager.java b/android/src/main/java/com/brentvatne/react/ReactVideoViewManager.java index b1fb1729..12fd4146 100644 --- a/android/src/main/java/com/brentvatne/react/ReactVideoViewManager.java +++ b/android/src/main/java/com/brentvatne/react/ReactVideoViewManager.java @@ -1,7 +1,7 @@ package com.brentvatne.react; import android.content.Context; -import android.media.MediaPlayer; +import com.brentvatne.react.ReactVideoView.Events; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; @@ -29,11 +29,6 @@ public class ReactVideoViewManager extends SimpleViewManager { public static final String PROP_MUTED = "muted"; public static final String PROP_VOLUME = "volume"; - public static final String EVENT_LOAD_START = "onVideoLoadStart"; - public static final String EVENT_LOAD = "onVideoLoad"; - public static final String EVENT_PROGRESS = "onVideoProgress"; - public static final String EVENT_END = "onVideoEnd"; - @Override public String getName() { return REACT_CLASS; @@ -47,12 +42,11 @@ public class ReactVideoViewManager extends SimpleViewManager { @Override @Nullable public Map getExportedCustomDirectEventTypeConstants() { - return MapBuilder.builder() - .put(EVENT_LOAD_START, MapBuilder.of("registrationName", EVENT_LOAD_START)) - .put(EVENT_LOAD, MapBuilder.of("registrationName", EVENT_LOAD)) - .put(EVENT_PROGRESS, MapBuilder.of("registrationName", EVENT_PROGRESS)) - .put(EVENT_END, MapBuilder.of("registrationName", EVENT_END)) - .build(); + MapBuilder.Builder builder = MapBuilder.builder(); + for (Events event : Events.values()) { + builder.put(event.toString(), MapBuilder.of("registrationName", event.toString())); + } + return builder.build(); } @Override @@ -91,39 +85,11 @@ public class ReactVideoViewManager extends SimpleViewManager { writableSrc.putBoolean(PROP_SRC_IS_NETWORK, isNetwork); WritableMap event = Arguments.createMap(); event.putMap(PROP_SRC, writableSrc); - eventEmitter.receiveEvent(videoView.getId(), EVENT_LOAD_START, event); + eventEmitter.receiveEvent(videoView.getId(), Events.EVENT_LOAD_START.toString(), event); - videoView.prepare(new MediaPlayer.OnPreparedListener() { - @Override - public void onPrepared(final MediaPlayer mp) { - mp.setScreenOnWhilePlaying(true); - - mp.setOnErrorListener(new MediaPlayer.OnErrorListener() { - @Override - public boolean onError(MediaPlayer mp, int what, int extra) { - // TODO: onVideoError - return false; - } - }); - - mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { - @Override - public void onCompletion(MediaPlayer mp) { - eventEmitter.receiveEvent(videoView.getId(), EVENT_END, null); - } - }); - - WritableMap event = Arguments.createMap(); - event.putDouble("duration", (double) mp.getDuration() / (double) 1000); - event.putDouble("currentTime", (double) mp.getCurrentPosition() / (double) 1000); - // TODO: Add canX properties. - eventEmitter.receiveEvent(videoView.getId(), EVENT_LOAD, event); - - videoView.applyModifiers(); - } - }); + videoView.prepare(); } catch (Exception e) { - // TODO: onVideoError + e.printStackTrace(); } }