@jwplayer/jwplayer-react-native 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,6 +2,7 @@ package com.jwplayer.rnjwplayer;
2
2
 
3
3
 
4
4
  import android.app.Activity;
5
+ import android.app.ActivityManager;
5
6
  import android.content.BroadcastReceiver;
6
7
  import android.content.Context;
7
8
  import android.content.Intent;
@@ -18,16 +19,20 @@ import android.os.Build;
18
19
  import android.os.Handler;
19
20
  import android.os.Looper;
20
21
  import android.util.Log;
21
- import android.view.Choreographer;
22
22
  import android.view.View;
23
23
  import android.view.ViewGroup;
24
24
  import android.view.Window;
25
25
  import android.view.WindowManager;
26
- import android.widget.FrameLayout;
27
26
  import android.widget.LinearLayout;
28
27
  import android.widget.RelativeLayout;
29
28
 
29
+ import androidx.annotation.NonNull;
30
30
  import androidx.appcompat.app.AppCompatActivity;
31
+ import androidx.lifecycle.Lifecycle;
32
+ import androidx.lifecycle.LifecycleEventObserver;
33
+ import androidx.lifecycle.LifecycleObserver;
34
+ import androidx.lifecycle.LifecycleOwner;
35
+ import androidx.lifecycle.LifecycleRegistry;
31
36
 
32
37
  import com.facebook.react.ReactActivity;
33
38
  import com.facebook.react.bridge.Arguments;
@@ -35,15 +40,18 @@ import com.facebook.react.bridge.LifecycleEventListener;
35
40
  import com.facebook.react.bridge.ReactApplicationContext;
36
41
  import com.facebook.react.bridge.ReadableArray;
37
42
  import com.facebook.react.bridge.ReadableMap;
43
+ import com.facebook.react.bridge.ReadableType;
44
+ import com.facebook.react.bridge.WritableArray;
38
45
  import com.facebook.react.bridge.WritableMap;
39
46
  import com.facebook.react.common.MapBuilder;
40
47
  import com.facebook.react.uimanager.ThemedReactContext;
41
48
  import com.facebook.react.uimanager.events.RCTEventEmitter;
42
49
  import com.google.common.collect.ImmutableMap;
43
50
  import com.google.gson.Gson;
44
- import com.jwplayer.pub.api.JsonHelper;
45
51
  import com.jwplayer.pub.api.JWPlayer;
52
+ import com.jwplayer.pub.api.JsonHelper;
46
53
  import com.jwplayer.pub.api.UiGroup;
54
+ import com.jwplayer.pub.api.background.MediaService;
47
55
  import com.jwplayer.pub.api.background.MediaServiceController;
48
56
  import com.jwplayer.pub.api.configuration.PlayerConfig;
49
57
  import com.jwplayer.pub.api.configuration.UiConfig;
@@ -110,9 +118,12 @@ import com.jwplayer.pub.api.fullscreen.delegates.DeviceOrientationDelegate;
110
118
  import com.jwplayer.pub.api.fullscreen.delegates.DialogLayoutDelegate;
111
119
  import com.jwplayer.pub.api.fullscreen.delegates.SystemUiDelegate;
112
120
  import com.jwplayer.pub.api.license.LicenseUtil;
121
+ import com.jwplayer.pub.api.media.captions.Caption;
113
122
  import com.jwplayer.pub.api.media.playlists.PlaylistItem;
114
123
  import com.jwplayer.ui.views.CueMarkerSeekbar;
115
124
 
125
+ import org.json.JSONObject;
126
+
116
127
  import java.util.ArrayList;
117
128
  import java.util.Arrays;
118
129
  import java.util.HashMap;
@@ -120,8 +131,6 @@ import java.util.List;
120
131
  import java.util.Map;
121
132
  import java.util.Objects;
122
133
 
123
- import org.json.JSONObject;
124
-
125
134
  public class RNJWPlayerView extends RelativeLayout implements
126
135
  VideoPlayerEvents.OnFullscreenListener,
127
136
  VideoPlayerEvents.OnReadyListener,
@@ -148,6 +157,7 @@ public class RNJWPlayerView extends RelativeLayout implements
148
157
  VideoPlayerEvents.OnCaptionsListListener,
149
158
  VideoPlayerEvents.OnCaptionsChangedListener,
150
159
  VideoPlayerEvents.OnMetaListener,
160
+ VideoPlayerEvents.PlaylistItemCallbackListener,
151
161
 
152
162
  CastingEvents.OnCastListener,
153
163
 
@@ -179,7 +189,7 @@ public class RNJWPlayerView extends RelativeLayout implements
179
189
 
180
190
  AudioManager.OnAudioFocusChangeListener,
181
191
 
182
- LifecycleEventListener {
192
+ LifecycleEventListener, LifecycleOwner {
183
193
  public RNJWPlayer mPlayerView = null;
184
194
  public JWPlayer mPlayer = null;
185
195
 
@@ -228,9 +238,18 @@ public class RNJWPlayerView extends RelativeLayout implements
228
238
  private MediaServiceController mMediaServiceController;
229
239
  private PipHandlerReceiver mReceiver = null;
230
240
 
241
+ // Add completion handler field
242
+ PlaylistItemDecision itemUpdatePromise = null;
243
+
231
244
  private void doBindService() {
232
245
  if (mMediaServiceController != null) {
233
- mMediaServiceController.bindService();
246
+ if (!isBackgroundAudioServiceRunning()) {
247
+ // This may not be your expected behavior, but is necessary to avoid crashing
248
+ // Do not use multiple player instances with background audio enabled
249
+
250
+ // don't rebind me if the service is already active with a player.
251
+ mMediaServiceController.bindService();
252
+ }
234
253
  }
235
254
  }
236
255
 
@@ -265,10 +284,23 @@ public class RNJWPlayerView extends RelativeLayout implements
265
284
  return superContext;
266
285
  }
267
286
 
287
+ private boolean isBackgroundAudioServiceRunning() {
288
+ ActivityManager manager = (ActivityManager) mAppContext.getSystemService(Context.ACTIVITY_SERVICE);
289
+ for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
290
+ if (MediaService.class.getName().equals(service.service.getClassName())) {
291
+ Log.w(TAG, "MediaService is already running with another player loaded. To avoid crashing, this player, "
292
+ + mPlayerView.getTag() + " will not be loaded into the background service.");
293
+ return true;
294
+ }
295
+ }
296
+ return false;
297
+ }
298
+
268
299
  public RNJWPlayerView(ThemedReactContext reactContext, ReactApplicationContext appContext) {
269
300
  super(getNonBuggyContext(reactContext, appContext));
270
301
  mAppContext = appContext;
271
302
 
303
+ registry.setCurrentState(Lifecycle.State.CREATED);
272
304
  mThemedReactContext = reactContext;
273
305
 
274
306
  mActivity = (ReactActivity) getActivity();
@@ -276,11 +308,25 @@ public class RNJWPlayerView extends RelativeLayout implements
276
308
  mWindow = mActivity.getWindow();
277
309
  }
278
310
 
311
+ if (mActivity != null) {
312
+ mActivity.getLifecycle().addObserver(lifecycleObserver);
313
+ }
314
+
279
315
  mRootView = mActivity.findViewById(android.R.id.content);
280
316
 
281
317
  getReactContext().addLifecycleEventListener(this);
282
318
  }
283
319
 
320
+ private LifecycleObserver lifecycleObserver = new LifecycleEventObserver() {
321
+ @Override
322
+ public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
323
+ if (event.getTargetState() == Lifecycle.State.DESTROYED) {
324
+ return; // no op: handled elsewhere
325
+ }
326
+ registry.setCurrentState(event.getTargetState());
327
+ }
328
+ };
329
+
284
330
  public ReactApplicationContext getAppContext() {
285
331
  return mAppContext;
286
332
  }
@@ -303,12 +349,44 @@ public class RNJWPlayerView extends RelativeLayout implements
303
349
  return mThemedReactContext.getReactApplicationContext().getCurrentActivity();
304
350
  }
305
351
 
352
+ // The registry for lifecycle events. Required by player object. Main use case if for garbage collection / teardown
353
+ private final LifecycleRegistry registry = new LifecycleRegistry(this);
354
+
355
+ @NonNull
356
+ @Override
357
+ public Lifecycle getLifecycle() {
358
+ return registry;
359
+ }
360
+
361
+ // // closest to `ondestroy` for a view without listening to the activity event
362
+ // // The activity event can be deceptive in React-Native
363
+ // @Override
364
+ // protected void onDetachedFromWindow() {
365
+ // super.onDetachedFromWindow();
366
+ // registry.setCurrentState(Lifecycle.State.DESTROYED);
367
+ // }
368
+
306
369
  public void destroyPlayer() {
307
370
  if (mPlayer != null) {
308
371
  unRegisterReceiver();
309
- mPlayer.deregisterActivityForPip();
372
+
373
+ // If we are casting we need to break the cast session as there is no simple
374
+ // way to reconnect to an existing session if the player that created it is dead
375
+
376
+ // If this doesn't match your use case, using a single player object and load content
377
+ // into it rather than creating a new player for every piece of content.
310
378
  mPlayer.stop();
311
379
 
380
+ // send signal to JW SDK player is destroyed
381
+ registry.setCurrentState(Lifecycle.State.DESTROYED);
382
+
383
+ // Stop listening to activities lifecycle
384
+ mActivity.getLifecycle().removeObserver(lifecycleObserver);
385
+ mPlayer.deregisterActivityForPip();
386
+
387
+ // Remove playlist item callback listener
388
+ mPlayer.removePlaylistItemCallbackListener();
389
+
312
390
  mPlayer.removeListeners(this,
313
391
  // VideoPlayerEvents
314
392
  EventType.READY,
@@ -386,7 +464,7 @@ public class RNJWPlayerView extends RelativeLayout implements
386
464
  }
387
465
  }
388
466
 
389
- public void setupPlayerView(Boolean backgroundAudioEnabled) {
467
+ public void setupPlayerView(Boolean backgroundAudioEnabled, Boolean playlistItemCallbackEnabled) {
390
468
  if (mPlayer != null) {
391
469
 
392
470
  mPlayer.addListeners(this,
@@ -400,6 +478,8 @@ public class RNJWPlayerView extends RelativeLayout implements
400
478
  EventType.SETUP_ERROR,
401
479
  EventType.BUFFER,
402
480
  EventType.TIME,
481
+ EventType.AUDIO_TRACKS,
482
+ EventType.AUDIO_TRACK_CHANGED,
403
483
  EventType.PLAYLIST,
404
484
  EventType.PLAYLIST_ITEM,
405
485
  EventType.PLAYLIST_COMPLETE,
@@ -449,13 +529,38 @@ public class RNJWPlayerView extends RelativeLayout implements
449
529
  } else {
450
530
  mPlayer.setFullscreenHandler(new fullscreenHandler());
451
531
  }
452
-
453
532
  mPlayer.allowBackgroundAudio(backgroundAudioEnabled);
533
+
534
+ if (playlistItemCallbackEnabled) {
535
+ mPlayer.setPlaylistItemCallbackListener(this);
536
+ }
537
+ }
538
+ }
539
+
540
+ public void resolveNextPlaylistItem(ReadableMap playlistItem) {
541
+ if (itemUpdatePromise == null) {
542
+ return;
543
+ }
544
+
545
+ if (playlistItem == null) {
546
+ itemUpdatePromise.continuePlayback();
547
+ itemUpdatePromise = null;
548
+ return;
549
+ }
550
+
551
+ try {
552
+ PlaylistItem updatedPlaylistItem = Util.getPlaylistItem(playlistItem);
553
+ itemUpdatePromise.modify(updatedPlaylistItem);
554
+ } catch (Exception exception) {
555
+ itemUpdatePromise.continuePlayback();
454
556
  }
557
+
558
+ itemUpdatePromise = null;
455
559
  }
456
560
 
457
561
  /**
458
562
  * Helper to build the a generic `ExtensibleFullscreenHandler` with small tweaks to play nice with Modals
563
+ *
459
564
  * @return {@link ExtensibleFullscreenHandler}
460
565
  */
461
566
  private ExtensibleFullscreenHandler createModalFullscreenHandler() {
@@ -554,6 +659,18 @@ public class RNJWPlayerView extends RelativeLayout implements
554
659
  return delegate;
555
660
  }
556
661
 
662
+ @Override
663
+ public void onBeforeNextPlaylistItem(PlaylistItemDecision playlistItemDecision, PlaylistItem nextItem, int indexOfNextItem) {
664
+ WritableMap event = Arguments.createMap();
665
+ Gson gson = new Gson();
666
+ event.putString("message", "onBeforeNextPlaylistItem");
667
+ event.putInt("index", indexOfNextItem);
668
+ event.putString("playlistItem", gson.toJson(nextItem));
669
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topBeforeNextPlaylistItem", event);
670
+
671
+ itemUpdatePromise = playlistItemDecision;
672
+ }
673
+
557
674
  private class fullscreenHandler implements FullscreenHandler {
558
675
  ViewGroup mPlayerViewContainer = (ViewGroup) mPlayerView.getParent();
559
676
  private View mDecorView;
@@ -622,6 +739,9 @@ public class RNJWPlayerView extends RelativeLayout implements
622
739
  mPlayerViewContainer.post(new Runnable() {
623
740
  @Override
624
741
  public void run() {
742
+ // View may not have been removed properly (especially if returning from PiP)
743
+ mPlayerViewContainer.removeView(mPlayerView);
744
+
625
745
  mPlayerViewContainer.addView(mPlayerView, new ViewGroup.LayoutParams(
626
746
  ViewGroup.LayoutParams.MATCH_PARENT,
627
747
  ViewGroup.LayoutParams.MATCH_PARENT));
@@ -714,6 +834,11 @@ public class RNJWPlayerView extends RelativeLayout implements
714
834
  mPlayer.setForceControlsVisibility(true);
715
835
  mPlayer.setForceControlsVisibility(false);
716
836
 
837
+ // If player was in fullscreen when going into PiP, we need to force it back out
838
+ if (mPlayer.getFullscreen()) {
839
+ mPlayer.setFullscreen(false, true);
840
+ }
841
+
717
842
  // Strip player view
718
843
  rootView.removeView(mPlayerView);
719
844
 
@@ -822,7 +947,7 @@ public class RNJWPlayerView extends RelativeLayout implements
822
947
  return differences.size() == 1 && differences.containsKey(keyName);
823
948
  }
824
949
 
825
- boolean playlistNotTheSame(ReadableMap prop) {
950
+ private boolean playlistNotTheSame(ReadableMap prop) {
826
951
  return prop.hasKey("playlist") && mPlaylistProp != prop.getArray("playlist") && !Arrays
827
952
  .deepEquals(new ReadableArray[]{mPlaylistProp}, new ReadableArray[]{prop.getArray("playlist")});
828
953
  }
@@ -834,6 +959,7 @@ public class RNJWPlayerView extends RelativeLayout implements
834
959
  JSONObject obj;
835
960
  PlayerConfig jwConfig = null;
836
961
  Boolean forceLegacy = prop.hasKey("forceLegacyConfig") ? prop.getBoolean("forceLegacyConfig") : false;
962
+ Boolean playlistItemCallbackEnabled = prop.hasKey("playlistItemCallbackEnabled") ? prop.getBoolean("playlistItemCallbackEnabled") : false;
837
963
  Boolean isJwConfig = false;
838
964
  if (!forceLegacy) {
839
965
  try {
@@ -940,9 +1066,11 @@ public class RNJWPlayerView extends RelativeLayout implements
940
1066
  ReadableArray uiGroupsArray = prop.getArray("hideUIGroups");
941
1067
  UiConfig.Builder hideConfigBuilder = new UiConfig.Builder().displayAllControls();
942
1068
  for (int i = 0; i < uiGroupsArray.size(); i++) {
943
- UiGroup uiGroup = GROUP_TYPES.get(uiGroupsArray.getString(i));
944
- if (uiGroup != null) {
945
- hideConfigBuilder.hide(uiGroup);
1069
+ if (uiGroupsArray.getType(i) == ReadableType.String) {
1070
+ UiGroup uiGroup = GROUP_TYPES.get(uiGroupsArray.getString(i));
1071
+ if (uiGroup != null) {
1072
+ hideConfigBuilder.hide(uiGroup);
1073
+ }
946
1074
  }
947
1075
  }
948
1076
  UiConfig hideJwControlbarUiConfig = hideConfigBuilder.build();
@@ -966,6 +1094,11 @@ public class RNJWPlayerView extends RelativeLayout implements
966
1094
  LinearLayout.LayoutParams.MATCH_PARENT));
967
1095
  addView(mPlayerView);
968
1096
 
1097
+ // Ensure we have a valid state before applying to the player
1098
+ registry.setCurrentState(registry.getCurrentState()); // This is a hack to ensure player and view know the lifecycle state
1099
+
1100
+ mPlayer = mPlayerView.getPlayer(this);
1101
+
969
1102
  if (prop.hasKey("controls")) { // Hack for controls hiding not working right away
970
1103
  mPlayerView.getPlayer().setControls(prop.getBoolean("controls"));
971
1104
  }
@@ -992,8 +1125,6 @@ public class RNJWPlayerView extends RelativeLayout implements
992
1125
  mPlayerView.exitFullScreenOnPortrait = exitFullScreenOnPortrait;
993
1126
  }
994
1127
 
995
- mPlayer = mPlayerView.getPlayer();
996
-
997
1128
  if (isJwConfig) {
998
1129
  mPlayer.setup(jwConfig);
999
1130
  } else {
@@ -1015,7 +1146,7 @@ public class RNJWPlayerView extends RelativeLayout implements
1015
1146
  // Legacy
1016
1147
  // This isn't the ideal way to do this on Android. All drawables/colors/themes shoudld
1017
1148
  // be targed using styling. See `https://docs.jwplayer.com/players/docs/android-styling-guide`
1018
- // for more information on how best to override the JWP styles using XML. If you are unsure of a
1149
+ // for more information on how best to override the JWP styles using XML. If you are unsure of a
1019
1150
  // color/drawable/theme, open an `Ask` issue.
1020
1151
  if (mColors != null) {
1021
1152
  if (mColors.hasKey("backgroundColor")) {
@@ -1068,12 +1199,10 @@ public class RNJWPlayerView extends RelativeLayout implements
1068
1199
  backgroundAudioEnabled = prop.getBoolean("backgroundAudioEnabled");
1069
1200
  }
1070
1201
 
1071
- setupPlayerView(backgroundAudioEnabled);
1202
+ setupPlayerView(backgroundAudioEnabled, playlistItemCallbackEnabled);
1072
1203
 
1073
1204
  if (backgroundAudioEnabled) {
1074
1205
  audioManager = (AudioManager) simpleContext.getSystemService(Context.AUDIO_SERVICE);
1075
- // Throws a fatal error if using a playlistURL instead of manually created playlist
1076
- // Related to SDK-11346
1077
1206
  mMediaServiceController = new MediaServiceController.Builder((AppCompatActivity) mActivity, mPlayer)
1078
1207
  .build();
1079
1208
  }
@@ -1232,7 +1361,7 @@ public class RNJWPlayerView extends RelativeLayout implements
1232
1361
  public void onAdLoaded(AdLoadedEvent adLoadedEvent) {
1233
1362
  WritableMap event = Arguments.createMap();
1234
1363
  event.putString("message", "onAdEvent");
1235
- event.putString("client", adLoadedEvent.getClient().toString());
1364
+ event.putInt("client", Util.getAdEventClientValue(adLoadedEvent));
1236
1365
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1237
1366
  }
1238
1367
 
@@ -1240,7 +1369,7 @@ public class RNJWPlayerView extends RelativeLayout implements
1240
1369
  public void onAdLoadedXml(AdLoadedXmlEvent adLoadedXmlEvent) {
1241
1370
  WritableMap event = Arguments.createMap();
1242
1371
  event.putString("message", "onAdEvent");
1243
- event.putString("client", adLoadedXmlEvent.getClient().toString());
1372
+ event.putInt("client", Util.getAdEventClientValue(adLoadedXmlEvent));
1244
1373
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1245
1374
  }
1246
1375
 
@@ -1249,7 +1378,8 @@ public class RNJWPlayerView extends RelativeLayout implements
1249
1378
  WritableMap event = Arguments.createMap();
1250
1379
  event.putString("message", "onAdEvent");
1251
1380
  event.putString("reason", adPauseEvent.getAdPauseReason().toString());
1252
- event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypePause));
1381
+ event.putInt("client", Util.getAdEventClientValue(adPauseEvent));
1382
+ event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypePause));
1253
1383
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1254
1384
  }
1255
1385
 
@@ -1258,7 +1388,8 @@ public class RNJWPlayerView extends RelativeLayout implements
1258
1388
  WritableMap event = Arguments.createMap();
1259
1389
  event.putString("message", "onAdEvent");
1260
1390
  event.putString("reason", adPlayEvent.getAdPlayReason().toString());
1261
- event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypePlay));
1391
+ event.putInt("client", Util.getAdEventClientValue(adPlayEvent));
1392
+ event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypePlay));
1262
1393
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1263
1394
  }
1264
1395
 
@@ -1266,8 +1397,8 @@ public class RNJWPlayerView extends RelativeLayout implements
1266
1397
  public void onAdBreakEnd(AdBreakEndEvent adBreakEndEvent) {
1267
1398
  WritableMap event = Arguments.createMap();
1268
1399
  event.putString("message", "onAdEvent");
1269
- event.putString("client", adBreakEndEvent.getClient().toString());
1270
- event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeAdBreakEnd));
1400
+ event.putInt("client", Util.getAdEventClientValue(adBreakEndEvent));
1401
+ event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeAdBreakEnd));
1271
1402
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1272
1403
  }
1273
1404
 
@@ -1275,8 +1406,8 @@ public class RNJWPlayerView extends RelativeLayout implements
1275
1406
  public void onAdBreakStart(AdBreakStartEvent adBreakStartEvent) {
1276
1407
  WritableMap event = Arguments.createMap();
1277
1408
  event.putString("message", "onAdEvent");
1278
- event.putString("client", adBreakStartEvent.getClient().toString());
1279
- event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeAdBreakStart));
1409
+ event.putInt("client", Util.getAdEventClientValue(adBreakStartEvent));
1410
+ event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeAdBreakStart));
1280
1411
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1281
1412
  }
1282
1413
 
@@ -1284,7 +1415,7 @@ public class RNJWPlayerView extends RelativeLayout implements
1284
1415
  public void onAdBreakIgnored(AdBreakIgnoredEvent adBreakIgnoredEvent) {
1285
1416
  WritableMap event = Arguments.createMap();
1286
1417
  event.putString("message", "onAdEvent");
1287
- event.putString("client", adBreakIgnoredEvent.getClient().toString());
1418
+ event.putInt("client", Util.getAdEventClientValue(adBreakIgnoredEvent));
1288
1419
  // missing type code
1289
1420
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1290
1421
  }
@@ -1293,8 +1424,8 @@ public class RNJWPlayerView extends RelativeLayout implements
1293
1424
  public void onAdClick(AdClickEvent adClickEvent) {
1294
1425
  WritableMap event = Arguments.createMap();
1295
1426
  event.putString("message", "onAdEvent");
1296
- event.putString("client", adClickEvent.getClient().toString());
1297
- event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeClicked));
1427
+ event.putInt("client", Util.getAdEventClientValue(adClickEvent));
1428
+ event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeClicked));
1298
1429
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1299
1430
  }
1300
1431
 
@@ -1302,7 +1433,8 @@ public class RNJWPlayerView extends RelativeLayout implements
1302
1433
  public void onAdCompanions(AdCompanionsEvent adCompanionsEvent) {
1303
1434
  WritableMap event = Arguments.createMap();
1304
1435
  event.putString("message", "onAdEvent");
1305
- event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeCompanion));
1436
+ event.putInt("client", Util.getAdEventClientValue(adCompanionsEvent));
1437
+ event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeCompanion));
1306
1438
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1307
1439
  }
1308
1440
 
@@ -1310,8 +1442,8 @@ public class RNJWPlayerView extends RelativeLayout implements
1310
1442
  public void onAdComplete(AdCompleteEvent adCompleteEvent) {
1311
1443
  WritableMap event = Arguments.createMap();
1312
1444
  event.putString("message", "onAdEvent");
1313
- event.putString("client", adCompleteEvent.getClient().toString());
1314
- event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeComplete));
1445
+ event.putInt("client", Util.getAdEventClientValue(adCompleteEvent));
1446
+ event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeComplete));
1315
1447
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1316
1448
  }
1317
1449
 
@@ -1331,7 +1463,7 @@ public class RNJWPlayerView extends RelativeLayout implements
1331
1463
  event.putString("message", "onPlayerAdWarning");
1332
1464
  event.putInt("code", adWarningEvent.getCode());
1333
1465
  event.putInt("adErrorCode", adWarningEvent.getAdErrorCode());
1334
- event.putString("error", adWarningEvent.getMessage());
1466
+ event.putString("warning", adWarningEvent.getMessage());
1335
1467
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topPlayerAdWarning", event);
1336
1468
  }
1337
1469
 
@@ -1339,8 +1471,8 @@ public class RNJWPlayerView extends RelativeLayout implements
1339
1471
  public void onAdImpression(AdImpressionEvent adImpressionEvent) {
1340
1472
  WritableMap event = Arguments.createMap();
1341
1473
  event.putString("message", "onAdEvent");
1342
- event.putString("client", adImpressionEvent.getClient().toString());
1343
- event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeImpression));
1474
+ event.putInt("client", Util.getAdEventClientValue(adImpressionEvent));
1475
+ event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeImpression));
1344
1476
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1345
1477
  }
1346
1478
 
@@ -1348,8 +1480,8 @@ public class RNJWPlayerView extends RelativeLayout implements
1348
1480
  public void onAdMeta(AdMetaEvent adMetaEvent) {
1349
1481
  WritableMap event = Arguments.createMap();
1350
1482
  event.putString("message", "onAdEvent");
1351
- event.putString("client", adMetaEvent.getClient().toString());
1352
- event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeMeta));
1483
+ event.putInt("client", Util.getAdEventClientValue(adMetaEvent));
1484
+ event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeMeta));
1353
1485
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1354
1486
  }
1355
1487
 
@@ -1357,8 +1489,8 @@ public class RNJWPlayerView extends RelativeLayout implements
1357
1489
  public void onAdRequest(AdRequestEvent adRequestEvent) {
1358
1490
  WritableMap event = Arguments.createMap();
1359
1491
  event.putString("message", "onAdEvent");
1360
- event.putString("client", adRequestEvent.getClient().toString());
1361
- event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeRequest));
1492
+ event.putInt("client", Util.getAdEventClientValue(adRequestEvent));
1493
+ event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeRequest));
1362
1494
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1363
1495
  }
1364
1496
 
@@ -1366,8 +1498,8 @@ public class RNJWPlayerView extends RelativeLayout implements
1366
1498
  public void onAdSchedule(AdScheduleEvent adScheduleEvent) {
1367
1499
  WritableMap event = Arguments.createMap();
1368
1500
  event.putString("message", "onAdEvent");
1369
- event.putString("client", adScheduleEvent.getClient().toString());
1370
- event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeSchedule));
1501
+ event.putInt("client", Util.getAdEventClientValue(adScheduleEvent));
1502
+ event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeSchedule));
1371
1503
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1372
1504
  }
1373
1505
 
@@ -1375,8 +1507,8 @@ public class RNJWPlayerView extends RelativeLayout implements
1375
1507
  public void onAdSkipped(AdSkippedEvent adSkippedEvent) {
1376
1508
  WritableMap event = Arguments.createMap();
1377
1509
  event.putString("message", "onAdEvent");
1378
- event.putString("client", adSkippedEvent.getClient().toString());
1379
- event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeSkipped));
1510
+ event.putInt("client", Util.getAdEventClientValue(adSkippedEvent));
1511
+ event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeSkipped));
1380
1512
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1381
1513
  }
1382
1514
 
@@ -1384,7 +1516,8 @@ public class RNJWPlayerView extends RelativeLayout implements
1384
1516
  public void onAdStarted(AdStartedEvent adStartedEvent) {
1385
1517
  WritableMap event = Arguments.createMap();
1386
1518
  event.putString("message", "onAdEvent");
1387
- event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeStarted));
1519
+ event.putInt("client", Util.getAdEventClientValue(adStartedEvent));
1520
+ event.putInt("type", Util.getAdEventTypeValue(Util.AdEventType.JWAdEventTypeStarted));
1388
1521
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1389
1522
  }
1390
1523
 
@@ -1437,6 +1570,38 @@ public class RNJWPlayerView extends RelativeLayout implements
1437
1570
 
1438
1571
  }
1439
1572
 
1573
+ // Captions Events
1574
+
1575
+ @Override
1576
+ public void onCaptionsChanged(CaptionsChangedEvent captionsChangedEvent) {
1577
+ WritableMap event = Arguments.createMap();
1578
+ event.putString("message", "onCaptionsChanged");
1579
+ event.putInt("index", captionsChangedEvent.getCurrentTrack());
1580
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topCaptionsChanged", event);
1581
+ }
1582
+
1583
+ @Override
1584
+ public void onCaptionsList(CaptionsListEvent captionsListEvent) {
1585
+ WritableMap event = Arguments.createMap();
1586
+ List<Caption> captionTrackList = captionsListEvent.getCaptions();
1587
+ WritableArray captionTracks = Arguments.createArray();
1588
+ if (captionTrackList != null) {
1589
+ for(int i = 0; i < captionTrackList.size(); i++) {
1590
+ WritableMap captionTrack = Arguments.createMap();
1591
+ Caption track = captionTrackList.get(i);
1592
+ captionTrack.putString("file", track.getFile());
1593
+ captionTrack.putString("label", track.getLabel());
1594
+ captionTrack.putBoolean("default", track.isDefault());
1595
+ captionTracks.pushMap(captionTrack);
1596
+ }
1597
+ }
1598
+ event.putString("message", "onCaptionsList");
1599
+ event.putInt("index", captionsListEvent.getCurrentCaptionIndex());
1600
+ event.putArray("tracks", captionTracks);
1601
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topCaptionsList", event);
1602
+
1603
+ }
1604
+
1440
1605
  // Player Events
1441
1606
 
1442
1607
  @Override
@@ -1485,6 +1650,7 @@ public class RNJWPlayerView extends RelativeLayout implements
1485
1650
  if (ex != null) {
1486
1651
  event.putString("error", ex.toString());
1487
1652
  event.putString("description", errorEvent.getMessage());
1653
+ event.putInt("errorCode", errorEvent.getErrorCode());
1488
1654
  }
1489
1655
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topPlayerError", event);
1490
1656
 
@@ -1635,6 +1801,8 @@ public class RNJWPlayerView extends RelativeLayout implements
1635
1801
  public void onSetupError(SetupErrorEvent setupErrorEvent) {
1636
1802
  WritableMap event = Arguments.createMap();
1637
1803
  event.putString("message", "onSetupError");
1804
+ event.putString("errorMessage", setupErrorEvent.getMessage());
1805
+ event.putInt("errorCode", setupErrorEvent.getCode());
1638
1806
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topSetupPlayerError", event);
1639
1807
 
1640
1808
  updateWakeLock(false);
@@ -1649,16 +1817,6 @@ public class RNJWPlayerView extends RelativeLayout implements
1649
1817
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topTime", event);
1650
1818
  }
1651
1819
 
1652
- @Override
1653
- public void onCaptionsChanged(CaptionsChangedEvent captionsChangedEvent) {
1654
-
1655
- }
1656
-
1657
- @Override
1658
- public void onCaptionsList(CaptionsListEvent captionsListEvent) {
1659
-
1660
- }
1661
-
1662
1820
  @Override
1663
1821
  public void onMeta(MetaEvent metaEvent) {
1664
1822
 
@@ -1678,6 +1836,17 @@ public class RNJWPlayerView extends RelativeLayout implements
1678
1836
 
1679
1837
  // Casting events
1680
1838
 
1839
+ private boolean mIsCastActive = false;
1840
+
1841
+ /**
1842
+ * Get if this player-view is currently casting
1843
+ *
1844
+ * @return true if casting
1845
+ */
1846
+ public boolean getIsCastActive() {
1847
+ return mIsCastActive;
1848
+ }
1849
+
1681
1850
  @Override
1682
1851
  public void onCast(CastEvent castEvent) {
1683
1852
  WritableMap event = Arguments.createMap();
@@ -1686,6 +1855,7 @@ public class RNJWPlayerView extends RelativeLayout implements
1686
1855
  event.putBoolean("active", castEvent.isActive());
1687
1856
  event.putBoolean("available", castEvent.isAvailable());
1688
1857
  getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topCasting", event);
1858
+ mIsCastActive = castEvent.isActive();
1689
1859
  // stop/start the background audio service if it's running and we're casting
1690
1860
  if (castEvent.isActive()) {
1691
1861
  doUnbindService();