@jwplayer/jwplayer-react-native 1.0.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.
Files changed (61) hide show
  1. package/.github/CODEOWNERS +2 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  4. package/.github/ISSUE_TEMPLATE/question.md +11 -0
  5. package/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  6. package/CODE_OF_CONDUCT.md +128 -0
  7. package/LICENSE +21 -0
  8. package/README.md +425 -0
  9. package/RNJWPlayer.podspec +44 -0
  10. package/android/.gradle/8.1.1/checksums/checksums.lock +0 -0
  11. package/android/.gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock +0 -0
  12. package/android/.gradle/8.1.1/dependencies-accessors/gc.properties +0 -0
  13. package/android/.gradle/8.1.1/fileChanges/last-build.bin +0 -0
  14. package/android/.gradle/8.1.1/fileHashes/fileHashes.lock +0 -0
  15. package/android/.gradle/8.1.1/gc.properties +0 -0
  16. package/android/.gradle/8.2/checksums/checksums.lock +0 -0
  17. package/android/.gradle/8.2/dependencies-accessors/dependencies-accessors.lock +0 -0
  18. package/android/.gradle/8.2/dependencies-accessors/gc.properties +0 -0
  19. package/android/.gradle/8.2/fileChanges/last-build.bin +0 -0
  20. package/android/.gradle/8.2/fileHashes/fileHashes.lock +0 -0
  21. package/android/.gradle/8.2/gc.properties +0 -0
  22. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  23. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  24. package/android/.gradle/config.properties +2 -0
  25. package/android/.gradle/vcs-1/gc.properties +0 -0
  26. package/android/.idea/gradle.xml +12 -0
  27. package/android/.idea/migrations.xml +10 -0
  28. package/android/.idea/misc.xml +10 -0
  29. package/android/.idea/vcs.xml +6 -0
  30. package/android/.idea/workspace.xml +54 -0
  31. package/android/build.gradle +110 -0
  32. package/android/local.properties +8 -0
  33. package/android/src/main/AndroidManifest.xml +25 -0
  34. package/android/src/main/java/com/jwplayer/rnjwplayer/ArrayUtil.java +129 -0
  35. package/android/src/main/java/com/jwplayer/rnjwplayer/CastOptionsProvider.java +55 -0
  36. package/android/src/main/java/com/jwplayer/rnjwplayer/MapUtil.java +136 -0
  37. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayer.java +76 -0
  38. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerAds.java +239 -0
  39. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerModule.java +526 -0
  40. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerPackage.java +30 -0
  41. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerView.java +1499 -0
  42. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerViewManager.java +171 -0
  43. package/android/src/main/java/com/jwplayer/rnjwplayer/Util.java +219 -0
  44. package/android/src/main/java/com/jwplayer/rnjwplayer/WidevineCallback.java +62 -0
  45. package/badges/license.svg +1 -0
  46. package/badges/version.svg +1 -0
  47. package/docs/legacy_readme.md +634 -0
  48. package/docs/props.md +43 -0
  49. package/docs/types.md +254 -0
  50. package/index.d.ts +564 -0
  51. package/index.js +699 -0
  52. package/ios/RNJWPlayer/RCTConvert+RNJWPlayer.swift +119 -0
  53. package/ios/RNJWPlayer/RNJWPlayer-Bridging-Header.h +5 -0
  54. package/ios/RNJWPlayer/RNJWPlayerAds.swift +260 -0
  55. package/ios/RNJWPlayer/RNJWPlayerModels.swift +149 -0
  56. package/ios/RNJWPlayer/RNJWPlayerView.swift +1837 -0
  57. package/ios/RNJWPlayer/RNJWPlayerViewController.swift +616 -0
  58. package/ios/RNJWPlayer/RNJWPlayerViewManager.m +132 -0
  59. package/ios/RNJWPlayer/RNJWPlayerViewManager.swift +500 -0
  60. package/ios/RNJWPlayer.xcodeproj/project.pbxproj +323 -0
  61. package/package.json +45 -0
@@ -0,0 +1,1499 @@
1
+ package com.jwplayer.rnjwplayer;
2
+
3
+
4
+ import android.app.Activity;
5
+ import android.content.Context;
6
+ import android.content.pm.ActivityInfo;
7
+ import android.graphics.Color;
8
+ import android.graphics.PorterDuff;
9
+ import android.graphics.drawable.Drawable;
10
+ import android.graphics.drawable.LayerDrawable;
11
+ import android.media.AudioAttributes;
12
+ import android.media.AudioFocusRequest;
13
+ import android.media.AudioManager;
14
+ import android.os.Build;
15
+ import android.util.Log;
16
+ import android.view.View;
17
+ import android.view.ViewGroup;
18
+ import android.view.Window;
19
+ import android.view.WindowManager;
20
+ import android.widget.LinearLayout;
21
+ import android.widget.RelativeLayout;
22
+
23
+ import androidx.appcompat.app.AppCompatActivity;
24
+
25
+ import com.facebook.react.ReactActivity;
26
+ import com.facebook.react.bridge.Arguments;
27
+ import com.facebook.react.bridge.LifecycleEventListener;
28
+ import com.facebook.react.bridge.ReactApplicationContext;
29
+ import com.facebook.react.bridge.ReadableArray;
30
+ import com.facebook.react.bridge.ReadableMap;
31
+ import com.facebook.react.bridge.WritableMap;
32
+ import com.facebook.react.common.MapBuilder;
33
+ import com.facebook.react.uimanager.ThemedReactContext;
34
+ import com.facebook.react.uimanager.events.RCTEventEmitter;
35
+ import com.google.common.collect.ImmutableMap;
36
+ import com.google.gson.Gson;
37
+ import com.jwplayer.pub.api.JsonHelper;
38
+ import com.jwplayer.pub.api.JWPlayer;
39
+ import com.jwplayer.pub.api.UiGroup;
40
+ import com.jwplayer.pub.api.background.MediaServiceController;
41
+ import com.jwplayer.pub.api.configuration.PlayerConfig;
42
+ import com.jwplayer.pub.api.configuration.UiConfig;
43
+ import com.jwplayer.pub.api.configuration.ads.AdvertisingConfig;
44
+ import com.jwplayer.pub.api.events.AdBreakEndEvent;
45
+ import com.jwplayer.pub.api.events.AdBreakIgnoredEvent;
46
+ import com.jwplayer.pub.api.events.AdBreakStartEvent;
47
+ import com.jwplayer.pub.api.events.AdClickEvent;
48
+ import com.jwplayer.pub.api.events.AdCompanionsEvent;
49
+ import com.jwplayer.pub.api.events.AdCompleteEvent;
50
+ import com.jwplayer.pub.api.events.AdErrorEvent;
51
+ import com.jwplayer.pub.api.events.AdImpressionEvent;
52
+ import com.jwplayer.pub.api.events.AdLoadedEvent;
53
+ import com.jwplayer.pub.api.events.AdLoadedXmlEvent;
54
+ import com.jwplayer.pub.api.events.AdMetaEvent;
55
+ import com.jwplayer.pub.api.events.AdPauseEvent;
56
+ import com.jwplayer.pub.api.events.AdPlayEvent;
57
+ import com.jwplayer.pub.api.events.AdRequestEvent;
58
+ import com.jwplayer.pub.api.events.AdScheduleEvent;
59
+ import com.jwplayer.pub.api.events.AdSkippedEvent;
60
+ import com.jwplayer.pub.api.events.AdStartedEvent;
61
+ import com.jwplayer.pub.api.events.AdTimeEvent;
62
+ import com.jwplayer.pub.api.events.AdViewableImpressionEvent;
63
+ import com.jwplayer.pub.api.events.AdWarningEvent;
64
+ import com.jwplayer.pub.api.events.AudioTrackChangedEvent;
65
+ import com.jwplayer.pub.api.events.AudioTracksEvent;
66
+ import com.jwplayer.pub.api.events.BeforeCompleteEvent;
67
+ import com.jwplayer.pub.api.events.BeforePlayEvent;
68
+ import com.jwplayer.pub.api.events.BufferEvent;
69
+ import com.jwplayer.pub.api.events.CaptionsChangedEvent;
70
+ import com.jwplayer.pub.api.events.CaptionsListEvent;
71
+ import com.jwplayer.pub.api.events.CastEvent;
72
+ import com.jwplayer.pub.api.events.CompleteEvent;
73
+ import com.jwplayer.pub.api.events.ControlBarVisibilityEvent;
74
+ import com.jwplayer.pub.api.events.ControlsEvent;
75
+ import com.jwplayer.pub.api.events.DisplayClickEvent;
76
+ import com.jwplayer.pub.api.events.ErrorEvent;
77
+ import com.jwplayer.pub.api.events.EventType;
78
+ import com.jwplayer.pub.api.events.FirstFrameEvent;
79
+ import com.jwplayer.pub.api.events.FullscreenEvent;
80
+ import com.jwplayer.pub.api.events.IdleEvent;
81
+ import com.jwplayer.pub.api.events.MetaEvent;
82
+ import com.jwplayer.pub.api.events.PauseEvent;
83
+ import com.jwplayer.pub.api.events.PipCloseEvent;
84
+ import com.jwplayer.pub.api.events.PipOpenEvent;
85
+ import com.jwplayer.pub.api.events.PlayEvent;
86
+ import com.jwplayer.pub.api.events.PlaybackRateChangedEvent;
87
+ import com.jwplayer.pub.api.events.PlaylistCompleteEvent;
88
+ import com.jwplayer.pub.api.events.PlaylistEvent;
89
+ import com.jwplayer.pub.api.events.PlaylistItemEvent;
90
+ import com.jwplayer.pub.api.events.ReadyEvent;
91
+ import com.jwplayer.pub.api.events.SeekEvent;
92
+ import com.jwplayer.pub.api.events.SeekedEvent;
93
+ import com.jwplayer.pub.api.events.SetupErrorEvent;
94
+ import com.jwplayer.pub.api.events.TimeEvent;
95
+ import com.jwplayer.pub.api.events.listeners.AdvertisingEvents;
96
+ import com.jwplayer.pub.api.events.listeners.CastingEvents;
97
+ import com.jwplayer.pub.api.events.listeners.PipPluginEvents;
98
+ import com.jwplayer.pub.api.events.listeners.VideoPlayerEvents;
99
+ import com.jwplayer.pub.api.fullscreen.FullscreenHandler;
100
+ import com.jwplayer.pub.api.license.LicenseUtil;
101
+ import com.jwplayer.pub.api.media.playlists.PlaylistItem;
102
+ import com.jwplayer.ui.views.CueMarkerSeekbar;
103
+
104
+ import java.util.ArrayList;
105
+ import java.util.Arrays;
106
+ import java.util.HashMap;
107
+ import java.util.List;
108
+ import java.util.Map;
109
+
110
+ import org.json.JSONObject;
111
+
112
+ public class RNJWPlayerView extends RelativeLayout implements
113
+ VideoPlayerEvents.OnFullscreenListener,
114
+ VideoPlayerEvents.OnReadyListener,
115
+ VideoPlayerEvents.OnPlayListener,
116
+ VideoPlayerEvents.OnPauseListener,
117
+ VideoPlayerEvents.OnCompleteListener,
118
+ VideoPlayerEvents.OnIdleListener,
119
+ VideoPlayerEvents.OnErrorListener,
120
+ VideoPlayerEvents.OnSetupErrorListener,
121
+ VideoPlayerEvents.OnBufferListener,
122
+ VideoPlayerEvents.OnTimeListener,
123
+ VideoPlayerEvents.OnPlaylistListener,
124
+ VideoPlayerEvents.OnPlaylistItemListener,
125
+ VideoPlayerEvents.OnPlaylistCompleteListener,
126
+ VideoPlayerEvents.OnAudioTracksListener,
127
+ VideoPlayerEvents.OnAudioTrackChangedListener,
128
+ VideoPlayerEvents.OnControlsListener,
129
+ VideoPlayerEvents.OnControlBarVisibilityListener,
130
+ VideoPlayerEvents.OnDisplayClickListener,
131
+ VideoPlayerEvents.OnFirstFrameListener,
132
+ VideoPlayerEvents.OnSeekListener,
133
+ VideoPlayerEvents.OnSeekedListener,
134
+ VideoPlayerEvents.OnPlaybackRateChangedListener,
135
+ VideoPlayerEvents.OnCaptionsListListener,
136
+ VideoPlayerEvents.OnCaptionsChangedListener,
137
+ VideoPlayerEvents.OnMetaListener,
138
+
139
+ CastingEvents.OnCastListener,
140
+
141
+ PipPluginEvents.OnPipCloseListener,
142
+ PipPluginEvents.OnPipOpenListener,
143
+
144
+ AdvertisingEvents.OnBeforePlayListener,
145
+ AdvertisingEvents.OnBeforeCompleteListener,
146
+ AdvertisingEvents.OnAdPauseListener,
147
+ AdvertisingEvents.OnAdPlayListener,
148
+ AdvertisingEvents.OnAdRequestListener,
149
+ AdvertisingEvents.OnAdScheduleListener,
150
+ AdvertisingEvents.OnAdStartedListener,
151
+ AdvertisingEvents.OnAdBreakStartListener,
152
+ AdvertisingEvents.OnAdBreakEndListener,
153
+ AdvertisingEvents.OnAdClickListener,
154
+ AdvertisingEvents.OnAdCompleteListener,
155
+ AdvertisingEvents.OnAdCompanionsListener,
156
+ AdvertisingEvents.OnAdErrorListener,
157
+ AdvertisingEvents.OnAdImpressionListener,
158
+ AdvertisingEvents.OnAdMetaListener,
159
+ AdvertisingEvents.OnAdSkippedListener,
160
+ AdvertisingEvents.OnAdTimeListener,
161
+ AdvertisingEvents.OnAdViewableImpressionListener,
162
+ AdvertisingEvents.OnAdBreakIgnoredListener,
163
+ AdvertisingEvents.OnAdWarningListener,
164
+ AdvertisingEvents.OnAdLoadedListener,
165
+ AdvertisingEvents.OnAdLoadedXmlListener,
166
+
167
+ AudioManager.OnAudioFocusChangeListener,
168
+
169
+ LifecycleEventListener {
170
+ public RNJWPlayer mPlayerView = null;
171
+ public JWPlayer mPlayer = null;
172
+
173
+ private ViewGroup mRootView;
174
+
175
+ // Props
176
+ ReadableMap mConfig = null;
177
+ ReadableArray mPlaylistProp = null;
178
+ ReadableMap mColors = null;
179
+
180
+ Boolean backgroundAudioEnabled = false;
181
+
182
+ Boolean landscapeOnFullScreen = false;
183
+ Boolean fullScreenOnLandscape = false;
184
+ Boolean portraitOnExitFullScreen = false;
185
+ Boolean exitFullScreenOnPortrait = false;
186
+
187
+ Number currentPlayingIndex;
188
+
189
+ private static final String TAG = "RNJWPlayerView";
190
+
191
+ static ReactActivity mActivity;
192
+
193
+ Window mWindow;
194
+
195
+ public static AudioManager audioManager;
196
+
197
+ final Object focusLock = new Object();
198
+
199
+ AudioFocusRequest focusRequest;
200
+
201
+ boolean hasAudioFocus = false;
202
+ boolean playbackDelayed = false;
203
+ boolean playbackNowAuthorized = false;
204
+ boolean userPaused = false;
205
+ boolean wasInterrupted = false;
206
+
207
+ private static int sessionDepth = 0;
208
+ boolean isInBackground = false;
209
+
210
+ private final ReactApplicationContext mAppContext;
211
+
212
+ private ThemedReactContext mThemedReactContext;
213
+
214
+ private MediaServiceController mMediaServiceController;
215
+
216
+ private void doBindService() {
217
+ if (mMediaServiceController != null) {
218
+ mMediaServiceController.bindService();
219
+ }
220
+ }
221
+
222
+ private void doUnbindService() {
223
+ if (mMediaServiceController != null) {
224
+ mMediaServiceController.unbindService();
225
+ mMediaServiceController = null;
226
+ }
227
+ }
228
+
229
+ private static boolean contextHasBug(Context context) {
230
+ return context == null ||
231
+ context.getResources() == null ||
232
+ context.getResources().getConfiguration() == null;
233
+ }
234
+
235
+ private static Context getNonBuggyContext(ThemedReactContext reactContext,
236
+ ReactApplicationContext appContext) {
237
+ Context superContext = reactContext;
238
+ if (!contextHasBug(appContext.getCurrentActivity())) {
239
+ superContext = appContext.getCurrentActivity();
240
+ } else if (contextHasBug(superContext)) {
241
+ // we have the bug! let's try to find a better context to use
242
+ if (!contextHasBug(reactContext.getCurrentActivity())) {
243
+ superContext = reactContext.getCurrentActivity();
244
+ } else if (!contextHasBug(reactContext.getApplicationContext())) {
245
+ superContext = reactContext.getApplicationContext();
246
+ } else {
247
+ // ¯\_(ツ)_/¯
248
+ }
249
+ }
250
+ return superContext;
251
+ }
252
+
253
+ public RNJWPlayerView(ThemedReactContext reactContext, ReactApplicationContext appContext) {
254
+ super(getNonBuggyContext(reactContext, appContext));
255
+ mAppContext = appContext;
256
+
257
+ mThemedReactContext = reactContext;
258
+
259
+ mActivity = (ReactActivity) getActivity();
260
+ if (mActivity != null) {
261
+ mWindow = mActivity.getWindow();
262
+ }
263
+
264
+ mRootView = mActivity.findViewById(android.R.id.content);
265
+
266
+ getReactContext().addLifecycleEventListener(this);
267
+ }
268
+
269
+ public ReactApplicationContext getAppContext() {
270
+ return mAppContext;
271
+ }
272
+
273
+ public ThemedReactContext getReactContext() {
274
+ return mThemedReactContext;
275
+ }
276
+
277
+ public Activity getActivity() {
278
+ if (!contextHasBug(mAppContext.getCurrentActivity())) {
279
+ return mAppContext.getCurrentActivity();
280
+ } else if (contextHasBug(mThemedReactContext)) {
281
+ if (!contextHasBug(mThemedReactContext.getCurrentActivity())) {
282
+ return mThemedReactContext.getCurrentActivity();
283
+ } else if (!contextHasBug(mThemedReactContext.getApplicationContext())) {
284
+ return (Activity) mThemedReactContext.getApplicationContext();
285
+ }
286
+ }
287
+
288
+ return mThemedReactContext.getReactApplicationContext().getCurrentActivity();
289
+ }
290
+
291
+ public void destroyPlayer() {
292
+ if (mPlayer != null) {
293
+ mPlayer.stop();
294
+
295
+ mPlayer.removeListeners(this,
296
+ // VideoPlayerEvents
297
+ EventType.READY,
298
+ EventType.PLAY,
299
+ EventType.PAUSE,
300
+ EventType.COMPLETE,
301
+ EventType.IDLE,
302
+ EventType.ERROR,
303
+ EventType.SETUP_ERROR,
304
+ EventType.BUFFER,
305
+ EventType.TIME,
306
+ EventType.PLAYLIST,
307
+ EventType.PLAYLIST_ITEM,
308
+ EventType.PLAYLIST_COMPLETE,
309
+ EventType.FIRST_FRAME,
310
+ EventType.CONTROLS,
311
+ EventType.CONTROLBAR_VISIBILITY,
312
+ EventType.DISPLAY_CLICK,
313
+ EventType.FULLSCREEN,
314
+ EventType.SEEK,
315
+ EventType.SEEKED,
316
+ EventType.PLAYBACK_RATE_CHANGED,
317
+ EventType.CAPTIONS_LIST,
318
+ EventType.CAPTIONS_CHANGED,
319
+ EventType.META,
320
+
321
+ // Ad events
322
+ EventType.BEFORE_PLAY,
323
+ EventType.BEFORE_COMPLETE,
324
+ EventType.AD_BREAK_START,
325
+ EventType.AD_BREAK_END,
326
+ EventType.AD_BREAK_IGNORED,
327
+ EventType.AD_CLICK,
328
+ EventType.AD_COMPANIONS,
329
+ EventType.AD_COMPLETE,
330
+ EventType.AD_ERROR,
331
+ EventType.AD_IMPRESSION,
332
+ EventType.AD_WARNING,
333
+ EventType.AD_LOADED,
334
+ EventType.AD_LOADED_XML,
335
+ EventType.AD_META,
336
+ EventType.AD_PAUSE,
337
+ EventType.AD_PLAY,
338
+ EventType.AD_REQUEST,
339
+ EventType.AD_SCHEDULE,
340
+ EventType.AD_SKIPPED,
341
+ EventType.AD_STARTED,
342
+ EventType.AD_TIME,
343
+ EventType.AD_VIEWABLE_IMPRESSION,
344
+ // Cast event
345
+ EventType.CAST,
346
+ // Pip events
347
+ EventType.PIP_CLOSE,
348
+ EventType.PIP_OPEN
349
+ );
350
+
351
+ mPlayer = null;
352
+ mPlayerView = null;
353
+
354
+ getReactContext().removeLifecycleEventListener(this);
355
+
356
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
357
+ if (audioManager != null && focusRequest != null) {
358
+ audioManager.abandonAudioFocusRequest(focusRequest);
359
+ }
360
+ } else {
361
+ if (audioManager != null) {
362
+ audioManager.abandonAudioFocus(this);
363
+ }
364
+ }
365
+
366
+ audioManager = null;
367
+
368
+ doUnbindService();
369
+ }
370
+ }
371
+
372
+ public void setupPlayerView(Boolean backgroundAudioEnabled) {
373
+ if (mPlayer != null) {
374
+
375
+ mPlayer.addListeners(this,
376
+ // VideoPlayerEvents
377
+ EventType.READY,
378
+ EventType.PLAY,
379
+ EventType.PAUSE,
380
+ EventType.COMPLETE,
381
+ EventType.IDLE,
382
+ EventType.ERROR,
383
+ EventType.SETUP_ERROR,
384
+ EventType.BUFFER,
385
+ EventType.TIME,
386
+ EventType.PLAYLIST,
387
+ EventType.PLAYLIST_ITEM,
388
+ EventType.PLAYLIST_COMPLETE,
389
+ EventType.FIRST_FRAME,
390
+ EventType.CONTROLS,
391
+ EventType.CONTROLBAR_VISIBILITY,
392
+ EventType.DISPLAY_CLICK,
393
+ EventType.FULLSCREEN,
394
+ EventType.SEEK,
395
+ EventType.SEEKED,
396
+ EventType.PLAYBACK_RATE_CHANGED,
397
+ EventType.CAPTIONS_LIST,
398
+ EventType.CAPTIONS_CHANGED,
399
+ EventType.META,
400
+ // Ad events
401
+ EventType.BEFORE_PLAY,
402
+ EventType.BEFORE_COMPLETE,
403
+ EventType.AD_BREAK_START,
404
+ EventType.AD_BREAK_END,
405
+ EventType.AD_BREAK_IGNORED,
406
+ EventType.AD_CLICK,
407
+ EventType.AD_COMPANIONS,
408
+ EventType.AD_COMPLETE,
409
+ EventType.AD_ERROR,
410
+ EventType.AD_IMPRESSION,
411
+ EventType.AD_WARNING,
412
+ EventType.AD_LOADED,
413
+ EventType.AD_LOADED_XML,
414
+ EventType.AD_META,
415
+ EventType.AD_PAUSE,
416
+ EventType.AD_PLAY,
417
+ EventType.AD_REQUEST,
418
+ EventType.AD_SCHEDULE,
419
+ EventType.AD_SKIPPED,
420
+ EventType.AD_STARTED,
421
+ EventType.AD_TIME,
422
+ EventType.AD_VIEWABLE_IMPRESSION,
423
+ // Cast event
424
+ EventType.CAST,
425
+ // Pip events
426
+ EventType.PIP_CLOSE,
427
+ EventType.PIP_OPEN
428
+ );
429
+
430
+ mPlayer.setFullscreenHandler(new fullscreenHandler());
431
+
432
+ mPlayer.allowBackgroundAudio(backgroundAudioEnabled);
433
+ }
434
+ }
435
+
436
+ private class fullscreenHandler implements FullscreenHandler {
437
+ ViewGroup mPlayerViewContainer = (ViewGroup) mPlayerView.getParent();
438
+ private View mDecorView;
439
+
440
+ @Override
441
+ public void onFullscreenRequested() {
442
+ mDecorView = mActivity.getWindow().getDecorView();
443
+
444
+ // Hide system ui
445
+ mDecorView.setSystemUiVisibility(
446
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hides bottom bar
447
+ | View.SYSTEM_UI_FLAG_FULLSCREEN // hides top bar
448
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY // prevents navigation bar from overriding
449
+ // exit-full-screen button. Swipe from side to access nav bar.
450
+ );
451
+
452
+ // Enter landscape mode for fullscreen videos
453
+ if (landscapeOnFullScreen) {
454
+ mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
455
+ }
456
+
457
+ mPlayerViewContainer = (ViewGroup) mPlayerView.getParent();
458
+
459
+ // Remove the JWPlayerView from the list item.
460
+ if (mPlayerViewContainer != null) {
461
+ mPlayerViewContainer.removeView(mPlayerView);
462
+ }
463
+
464
+ // Initialize a new rendering surface.
465
+ // mPlayerView.initializeSurface();
466
+
467
+ // Add the JWPlayerView to the RootView as soon as the UI thread is ready.
468
+ mRootView.post(new Runnable() {
469
+ @Override
470
+ public void run() {
471
+ mRootView.addView(mPlayerView, new ViewGroup.LayoutParams(
472
+ ViewGroup.LayoutParams.MATCH_PARENT,
473
+ ViewGroup.LayoutParams.MATCH_PARENT));
474
+ }
475
+ });
476
+
477
+ WritableMap eventEnterFullscreen = Arguments.createMap();
478
+ eventEnterFullscreen.putString("message", "onFullscreenRequested");
479
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(
480
+ getId(),
481
+ "topFullScreenRequested",
482
+ eventEnterFullscreen);
483
+ }
484
+
485
+ @Override
486
+ public void onFullscreenExitRequested() {
487
+ mDecorView.setSystemUiVisibility(
488
+ View.SYSTEM_UI_FLAG_VISIBLE // clear the hide system flags
489
+ );
490
+
491
+ // Enter portrait mode
492
+ if (portraitOnExitFullScreen) {
493
+ mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
494
+ }
495
+
496
+ // Remove the player view from the root ViewGroup.
497
+ mRootView.removeView(mPlayerView);
498
+
499
+ // As soon as the UI thread has finished processing the current message queue it
500
+ // should add the JWPlayerView back to the list item.
501
+ mPlayerViewContainer.post(new Runnable() {
502
+ @Override
503
+ public void run() {
504
+ mPlayerViewContainer.addView(mPlayerView, new ViewGroup.LayoutParams(
505
+ ViewGroup.LayoutParams.MATCH_PARENT,
506
+ ViewGroup.LayoutParams.MATCH_PARENT));
507
+ mPlayerView.layout(mPlayerViewContainer.getLeft(), mPlayerViewContainer.getTop(),
508
+ mPlayerViewContainer.getRight(), mPlayerViewContainer.getBottom());
509
+ }
510
+ });
511
+
512
+ WritableMap eventExitFullscreen = Arguments.createMap();
513
+ eventExitFullscreen.putString("message", "onFullscreenExitRequested");
514
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(
515
+ getId(),
516
+ "topFullScreenExitRequested",
517
+ eventExitFullscreen);
518
+ }
519
+
520
+ @Override
521
+ public void onAllowRotationChanged(boolean b) {
522
+ Log.e(TAG, "onAllowRotationChanged: " + b );
523
+ }
524
+
525
+ @Override
526
+ public void onAllowFullscreenPortraitChanged(boolean allowFullscreenPortrait) {
527
+ Log.e(TAG, "onAllowFullscreenPortraitChanged: " + allowFullscreenPortrait );
528
+ }
529
+
530
+ @Override
531
+ public void updateLayoutParams(ViewGroup.LayoutParams layoutParams) {
532
+ // View.setSystemUiVisibility(int).
533
+ // Log.e(TAG, "updateLayoutParams: "+layoutParams );
534
+ }
535
+
536
+ @Override
537
+ public void setUseFullscreenLayoutFlags(boolean b) {
538
+ // View.setSystemUiVisibility(int).
539
+ // Log.e(TAG, "setUseFullscreenLayoutFlags: "+b );
540
+ }
541
+ }
542
+
543
+ public void setConfig(ReadableMap prop) {
544
+ if (mConfig == null || !mConfig.equals(prop)) {
545
+ if (mConfig != null && isOnlyDiff(prop, "playlist") && mPlayer != null) { // still safe check, even with JW
546
+ // JSON change
547
+ PlayerConfig oldConfig = mPlayer.getConfig();
548
+ PlayerConfig config = new PlayerConfig.Builder()
549
+ .autostart(oldConfig.getAutostart())
550
+ .nextUpOffset(oldConfig.getNextUpOffset())
551
+ .repeat(oldConfig.getRepeat())
552
+ .relatedConfig(oldConfig.getRelatedConfig())
553
+ .displayDescription(oldConfig.getDisplayDescription())
554
+ .displayTitle(oldConfig.getDisplayTitle())
555
+ .advertisingConfig(oldConfig.getAdvertisingConfig())
556
+ .stretching(oldConfig.getStretching())
557
+ .uiConfig(oldConfig.getUiConfig())
558
+ .playlist(Util.createPlaylist(mPlaylistProp))
559
+ .allowCrossProtocolRedirects(oldConfig.getAllowCrossProtocolRedirects())
560
+ .preload(oldConfig.getPreload())
561
+ .useTextureView(oldConfig.useTextureView())
562
+ .thumbnailPreview(oldConfig.getThumbnailPreview())
563
+ .mute(oldConfig.getMute())
564
+ .build();
565
+
566
+ mPlayer.setup(config);
567
+ } else {
568
+ if (prop.hasKey("license")) {
569
+ new LicenseUtil().setLicenseKey(getReactContext(), prop.getString("license"));
570
+ } else {
571
+ Log.e(TAG, "JW SDK license not set");
572
+ }
573
+
574
+ // The entire config is different (other than the "playlist" key)
575
+ this.setupPlayer(prop);
576
+ }
577
+ } else {
578
+ // No change
579
+ }
580
+
581
+ mConfig = prop;
582
+ }
583
+
584
+ public boolean isOnlyDiff(ReadableMap prop, String keyName) {
585
+ // Convert ReadableMap to HashMap
586
+ Map<String, Object> mConfigMap = mConfig.toHashMap();
587
+ Map<String, Object> propMap = prop.toHashMap();
588
+
589
+ Map<String, Object> differences = new HashMap<>();
590
+
591
+ // Find keys in mConfig that aren't in prop or have different values
592
+ for (Map.Entry<String, Object> entry : mConfigMap.entrySet()) {
593
+ String key = entry.getKey();
594
+ Object value = entry.getValue();
595
+
596
+ if (!propMap.containsKey(key) || !propMap.get(key).equals(value)) {
597
+ differences.put(key, value);
598
+ }
599
+ }
600
+
601
+ // Find keys in prop that aren't in mConfig
602
+ for (String key : propMap.keySet()) {
603
+ if (!mConfigMap.containsKey(key)) {
604
+ differences.put(key, propMap.get(key));
605
+ }
606
+ }
607
+
608
+ return differences.size() == 1 && differences.containsKey(keyName);
609
+ }
610
+
611
+ boolean playlistNotTheSame(ReadableMap prop) {
612
+ return prop.hasKey("playlist") && mPlaylistProp != prop.getArray("playlist") && !Arrays
613
+ .deepEquals(new ReadableArray[] { mPlaylistProp }, new ReadableArray[] { prop.getArray("playlist") });
614
+ }
615
+
616
+ private void setupPlayer(ReadableMap prop) {
617
+ // Legacy
618
+ PlayerConfig.Builder configBuilder = new PlayerConfig.Builder();
619
+
620
+ JSONObject obj;
621
+ PlayerConfig jwConfig = null;
622
+ Boolean forceLegacy = prop.hasKey("forceLegacyConfig") ? prop.getBoolean("forceLegacyConfig") : false;
623
+ Boolean isJwConfig = false;
624
+ if(!forceLegacy){
625
+ try {
626
+ obj = MapUtil.toJSONObject(prop);
627
+ jwConfig = JsonHelper.parseConfigJson(obj);
628
+ isJwConfig = true;
629
+ } catch (Exception ex) {
630
+ Log.e("RNJWPlayerView", ex.toString());
631
+ isJwConfig = false; // not a valid jw config. Try to setup in legacy
632
+ }
633
+ }
634
+
635
+ if (!isJwConfig) {
636
+ // Legacy
637
+ if (playlistNotTheSame(prop)) {
638
+ List<PlaylistItem> playlist = new ArrayList<>();
639
+ mPlaylistProp = prop.getArray("playlist");
640
+ if (mPlaylistProp != null && mPlaylistProp.size() > 0) {
641
+
642
+ int j = 0;
643
+ while (mPlaylistProp.size() > j) {
644
+ ReadableMap playlistItem = mPlaylistProp.getMap(j);
645
+
646
+ PlaylistItem newPlayListItem = Util.getPlaylistItem((playlistItem));
647
+ playlist.add(newPlayListItem);
648
+ j++;
649
+ }
650
+ }
651
+
652
+ configBuilder.playlist(playlist);
653
+ }
654
+
655
+ // Legacy
656
+ if (prop.hasKey("autostart")) {
657
+ boolean autostart = prop.getBoolean("autostart");
658
+ configBuilder.autostart(autostart);
659
+ }
660
+
661
+ // Legacy
662
+ if (prop.hasKey("nextUpStyle")) {
663
+ ReadableMap nextUpStyle = prop.getMap("nextUpStyle");
664
+ if (nextUpStyle != null && nextUpStyle.hasKey("offsetSeconds")
665
+ && nextUpStyle.hasKey("offsetPercentage")) {
666
+ int offsetSeconds = prop.getInt("offsetSeconds");
667
+ int offsetPercentage = prop.getInt("offsetPercentage");
668
+ configBuilder.nextUpOffset(offsetSeconds).nextUpOffsetPercentage(offsetPercentage);
669
+ }
670
+ }
671
+
672
+ // Legacy
673
+ if (prop.hasKey("repeat")) {
674
+ boolean repeat = prop.getBoolean("repeat");
675
+ configBuilder.repeat(repeat);
676
+ }
677
+
678
+ // Legacy
679
+ if (prop.hasKey("styling")) {
680
+ ReadableMap styling = prop.getMap("styling");
681
+ if (styling != null) {
682
+ if (styling.hasKey("displayDescription")) {
683
+ boolean displayDescription = styling.getBoolean("displayDescription");
684
+ configBuilder.displayDescription(displayDescription);
685
+ }
686
+
687
+ if (styling.hasKey("displayTitle")) {
688
+ boolean displayTitle = styling.getBoolean("displayTitle");
689
+ configBuilder.displayTitle(displayTitle);
690
+ }
691
+
692
+ if (styling.hasKey("colors")) {
693
+ mColors = styling.getMap("colors");
694
+ }
695
+ }
696
+ }
697
+
698
+ // Legacy
699
+ if (prop.hasKey("advertising")) {
700
+ ReadableMap ads = prop.getMap("advertising");
701
+ AdvertisingConfig advertisingConfig = RNJWPlayerAds.getAdvertisingConfig(ads);
702
+ if (advertisingConfig != null) {
703
+ configBuilder.advertisingConfig(advertisingConfig);
704
+ }
705
+ }
706
+
707
+ // Legacy
708
+ if (prop.hasKey("stretching")) {
709
+ String stretching = prop.getString("stretching");
710
+ configBuilder.stretching(stretching);
711
+ }
712
+
713
+ // Legacy
714
+ // this isn't the ideal way to do controls...
715
+ // Better to just expose the `.setControls` method
716
+ if (prop.hasKey("controls")) {
717
+ boolean controls = prop.getBoolean("controls");
718
+ if (!controls) {
719
+ UiConfig uiConfig = new UiConfig.Builder().hideAllControls().build();
720
+ configBuilder.uiConfig(uiConfig);
721
+ }
722
+ }
723
+
724
+ // Legacy
725
+ if (prop.hasKey("hideUIGroups")) {
726
+ ReadableArray uiGroupsArray = prop.getArray("hideUIGroups");
727
+ UiConfig.Builder hideConfigBuilder = new UiConfig.Builder().displayAllControls();
728
+ for (int i = 0; i < uiGroupsArray.size(); i++) {
729
+ UiGroup uiGroup = GROUP_TYPES.get(uiGroupsArray.getString(i));
730
+ if (uiGroup != null) {
731
+ hideConfigBuilder.hide(uiGroup);
732
+ }
733
+ }
734
+ UiConfig hideJwControlbarUiConfig = hideConfigBuilder.build();
735
+ configBuilder.uiConfig(hideJwControlbarUiConfig);
736
+ }
737
+ }
738
+
739
+ Context simpleContext = getNonBuggyContext(getReactContext(), getAppContext());
740
+
741
+ this.destroyPlayer();
742
+
743
+ mPlayerView = new RNJWPlayer(simpleContext);
744
+
745
+ mPlayerView.setFocusable(true);
746
+ mPlayerView.setFocusableInTouchMode(true);
747
+
748
+ setLayoutParams(
749
+ new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
750
+ mPlayerView.setLayoutParams(new LinearLayout.LayoutParams(
751
+ LinearLayout.LayoutParams.MATCH_PARENT,
752
+ LinearLayout.LayoutParams.MATCH_PARENT));
753
+ addView(mPlayerView);
754
+
755
+ if (prop.hasKey("controls")) { // Hack for controls hiding not working right away
756
+ mPlayerView.getPlayer().setControls(prop.getBoolean("controls"));
757
+ }
758
+
759
+ if (prop.hasKey("fullScreenOnLandscape")) {
760
+ fullScreenOnLandscape = prop.getBoolean("fullScreenOnLandscape");
761
+ mPlayerView.fullScreenOnLandscape = fullScreenOnLandscape;
762
+ }
763
+
764
+ if (prop.hasKey("exitFullScreenOnPortrait")) {
765
+ exitFullScreenOnPortrait = prop.getBoolean("exitFullScreenOnPortrait");
766
+ mPlayerView.exitFullScreenOnPortrait = exitFullScreenOnPortrait;
767
+ }
768
+
769
+ mPlayer = mPlayerView.getPlayer();
770
+
771
+ if (isJwConfig) {
772
+ mPlayer.setup(jwConfig);
773
+ } else {
774
+ PlayerConfig playerConfig = configBuilder.build();
775
+ mPlayer.setup(playerConfig);
776
+ }
777
+
778
+ if (mActivity != null && prop.hasKey("pipEnabled")) {
779
+ boolean pipEnabled = prop.getBoolean("pipEnabled");
780
+ if (pipEnabled) {
781
+ mPlayer.registerActivityForPip(mActivity, mActivity.getSupportActionBar());
782
+ } else {
783
+ mPlayer.deregisterActivityForPip();
784
+ }
785
+ }
786
+
787
+ // Legacy
788
+ // This isn't the ideal way to do this on Android
789
+ if (mColors != null) {
790
+ if (mColors.hasKey("backgroundColor")) {
791
+ mPlayerView.setBackgroundColor(Color.parseColor("#" + mColors.getString("backgroundColor")));
792
+ }
793
+
794
+ if (mColors.hasKey("buttons")) {
795
+
796
+ }
797
+
798
+ if (mColors.hasKey("timeslider")) {
799
+ CueMarkerSeekbar seekBar = findViewById(com.longtailvideo.jwplayer.R.id.controlbar_seekbar);
800
+ ReadableMap timeslider = mColors.getMap("timeslider");
801
+ if (timeslider != null) {
802
+ LayerDrawable progressDrawable = (LayerDrawable) seekBar.getProgressDrawable();
803
+
804
+ if (timeslider.hasKey("progress")) {
805
+ // seekBar.getProgressDrawable().setColorFilter(Color.parseColor("#" +
806
+ // timeslider.getString("progress")), PorterDuff.Mode.SRC_IN);
807
+ Drawable processDrawable = progressDrawable.findDrawableByLayerId(android.R.id.progress);
808
+ processDrawable.setColorFilter(Color.parseColor("#" + timeslider.getString("progress")),
809
+ PorterDuff.Mode.SRC_IN);
810
+ }
811
+
812
+ if (timeslider.hasKey("buffer")) {
813
+ Drawable secondaryProgressDrawable = progressDrawable
814
+ .findDrawableByLayerId(android.R.id.secondaryProgress);
815
+ secondaryProgressDrawable.setColorFilter(Color.parseColor("#" + timeslider.getString("buffer")),
816
+ PorterDuff.Mode.SRC_IN);
817
+ }
818
+
819
+ if (timeslider.hasKey("rail")) {
820
+ Drawable backgroundDrawable = progressDrawable.findDrawableByLayerId(android.R.id.background);
821
+ backgroundDrawable.setColorFilter(Color.parseColor("#" + timeslider.getString("rail")),
822
+ PorterDuff.Mode.SRC_IN);
823
+ }
824
+
825
+ if (timeslider.hasKey("thumb")) {
826
+ seekBar.getThumb().setColorFilter(Color.parseColor("#" + timeslider.getString("thumb")),
827
+ PorterDuff.Mode.SRC_IN);
828
+ }
829
+ }
830
+ }
831
+ }
832
+
833
+ // Needed to handle volume control
834
+ audioManager = (AudioManager) simpleContext.getSystemService(Context.AUDIO_SERVICE);
835
+
836
+ if (prop.hasKey("backgroundAudioEnabled")) {
837
+ backgroundAudioEnabled = prop.getBoolean("backgroundAudioEnabled");
838
+ }
839
+
840
+ setupPlayerView(backgroundAudioEnabled);
841
+
842
+ if (backgroundAudioEnabled) {
843
+ audioManager = (AudioManager) simpleContext.getSystemService(Context.AUDIO_SERVICE);
844
+ // Throws a fatal error if using a playlistURL instead of manually created playlist
845
+ // Related to SDK-11346
846
+ mMediaServiceController = new MediaServiceController.Builder((AppCompatActivity) mActivity, mPlayer)
847
+ .build();
848
+ }
849
+ }
850
+
851
+ // Audio Focus
852
+
853
+ public void requestAudioFocus() {
854
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
855
+ if (hasAudioFocus) {
856
+ return;
857
+ }
858
+
859
+ if (audioManager != null) {
860
+ AudioAttributes playbackAttributes = new AudioAttributes.Builder()
861
+ .setUsage(AudioAttributes.USAGE_MEDIA)
862
+ .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) // CONTENT_TYPE_SPEECH
863
+ .build();
864
+ focusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
865
+ .setAudioAttributes(playbackAttributes)
866
+ .setAcceptsDelayedFocusGain(true)
867
+ // .setWillPauseWhenDucked(true)
868
+ .setOnAudioFocusChangeListener(this)
869
+ .build();
870
+
871
+ int res = audioManager.requestAudioFocus(focusRequest);
872
+ synchronized (focusLock) {
873
+ if (res == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
874
+ playbackNowAuthorized = false;
875
+ } else if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
876
+ playbackNowAuthorized = true;
877
+ hasAudioFocus = true;
878
+ } else if (res == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
879
+ playbackDelayed = true;
880
+ playbackNowAuthorized = false;
881
+ }
882
+ }
883
+ Log.e(TAG, "audioRequest: " + res);
884
+ }
885
+ } else {
886
+ int result = 0;
887
+ if (audioManager != null) {
888
+ if (hasAudioFocus) {
889
+ return;
890
+ }
891
+
892
+ result = audioManager.requestAudioFocus(this,
893
+ // Use the music stream.
894
+ AudioManager.STREAM_MUSIC,
895
+ // Request permanent focus.
896
+ AudioManager.AUDIOFOCUS_GAIN);
897
+ }
898
+ if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
899
+ hasAudioFocus = true;
900
+ }
901
+ Log.e(TAG, "audioRequest: " + result);
902
+ }
903
+ }
904
+
905
+
906
+ public void lowerApiOnAudioFocus(int focusChange) {
907
+ if (mPlayer != null) {
908
+ int initVolume = mPlayer.getVolume();
909
+
910
+ switch (focusChange) {
911
+ case AudioManager.AUDIOFOCUS_GAIN:
912
+ if (!userPaused) {
913
+ setVolume(initVolume);
914
+
915
+ boolean autostart = mPlayer.getConfig().getAutostart();
916
+ if (autostart) {
917
+ mPlayer.play();
918
+ }
919
+ }
920
+ break;
921
+ case AudioManager.AUDIOFOCUS_LOSS:
922
+ mPlayer.pause();
923
+ wasInterrupted = true;
924
+ hasAudioFocus = false;
925
+ break;
926
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
927
+ mPlayer.pause();
928
+ wasInterrupted = true;
929
+ break;
930
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
931
+ setVolume(initVolume / 2);
932
+ break;
933
+ }
934
+ }
935
+ }
936
+
937
+ public void onAudioFocusChange(int focusChange) {
938
+ if (mPlayer != null) {
939
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
940
+ int initVolume = mPlayer.getVolume();
941
+
942
+ switch (focusChange) {
943
+ case AudioManager.AUDIOFOCUS_GAIN:
944
+ if (playbackDelayed || !userPaused) {
945
+ synchronized (focusLock) {
946
+ playbackDelayed = false;
947
+ }
948
+
949
+ setVolume(initVolume);
950
+
951
+ boolean autostart = mPlayer.getConfig().getAutostart();
952
+ if (autostart) {
953
+ mPlayer.play();
954
+ }
955
+ }
956
+ break;
957
+ case AudioManager.AUDIOFOCUS_LOSS:
958
+ mPlayer.pause();
959
+ synchronized (focusLock) {
960
+ wasInterrupted = true;
961
+ playbackDelayed = false;
962
+ }
963
+ hasAudioFocus = false;
964
+ break;
965
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
966
+ mPlayer.pause();
967
+ synchronized (focusLock) {
968
+ wasInterrupted = true;
969
+ playbackDelayed = false;
970
+ }
971
+ break;
972
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
973
+ setVolume(initVolume / 2);
974
+ break;
975
+ }
976
+ } else {
977
+ lowerApiOnAudioFocus(focusChange);
978
+ }
979
+ }
980
+ }
981
+
982
+ private void setVolume(int volume) {
983
+ if (!mPlayer.getMute()) {
984
+ mPlayer.setVolume(volume);
985
+ }
986
+ }
987
+
988
+ private void updateWakeLock(boolean enable) {
989
+ if (mWindow != null) {
990
+ if (enable && !isInBackground) {
991
+ mWindow.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
992
+ } else {
993
+ mWindow.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
994
+ }
995
+ }
996
+ }
997
+
998
+ // Ad events
999
+
1000
+ @Override
1001
+ public void onAdLoaded(AdLoadedEvent adLoadedEvent) {
1002
+ WritableMap event = Arguments.createMap();
1003
+ event.putString("message", "onAdEvent");
1004
+ event.putString("client", adLoadedEvent.getClient().toString());
1005
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1006
+ }
1007
+
1008
+ @Override
1009
+ public void onAdLoadedXml(AdLoadedXmlEvent adLoadedXmlEvent) {
1010
+ WritableMap event = Arguments.createMap();
1011
+ event.putString("message", "onAdEvent");
1012
+ event.putString("client", adLoadedXmlEvent.getClient().toString());
1013
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1014
+ }
1015
+
1016
+ @Override
1017
+ public void onAdPause(AdPauseEvent adPauseEvent) {
1018
+ WritableMap event = Arguments.createMap();
1019
+ event.putString("message", "onAdEvent");
1020
+ event.putString("reason", adPauseEvent.getAdPauseReason().toString());
1021
+ event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypePause));
1022
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1023
+ }
1024
+
1025
+ @Override
1026
+ public void onAdPlay(AdPlayEvent adPlayEvent) {
1027
+ WritableMap event = Arguments.createMap();
1028
+ event.putString("message", "onAdEvent");
1029
+ event.putString("reason", adPlayEvent.getAdPlayReason().toString());
1030
+ event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypePlay));
1031
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1032
+ }
1033
+
1034
+ @Override
1035
+ public void onAdBreakEnd(AdBreakEndEvent adBreakEndEvent) {
1036
+ WritableMap event = Arguments.createMap();
1037
+ event.putString("message", "onAdEvent");
1038
+ event.putString("client", adBreakEndEvent.getClient().toString());
1039
+ event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeAdBreakEnd));
1040
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1041
+ }
1042
+
1043
+ @Override
1044
+ public void onAdBreakStart(AdBreakStartEvent adBreakStartEvent) {
1045
+ WritableMap event = Arguments.createMap();
1046
+ event.putString("message", "onAdEvent");
1047
+ event.putString("client", adBreakStartEvent.getClient().toString());
1048
+ event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeAdBreakStart));
1049
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1050
+ }
1051
+
1052
+ @Override
1053
+ public void onAdBreakIgnored(AdBreakIgnoredEvent adBreakIgnoredEvent) {
1054
+ WritableMap event = Arguments.createMap();
1055
+ event.putString("message", "onAdEvent");
1056
+ event.putString("client", adBreakIgnoredEvent.getClient().toString());
1057
+ // missing type code
1058
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1059
+ }
1060
+
1061
+ @Override
1062
+ public void onAdClick(AdClickEvent adClickEvent) {
1063
+ WritableMap event = Arguments.createMap();
1064
+ event.putString("message", "onAdEvent");
1065
+ event.putString("client", adClickEvent.getClient().toString());
1066
+ event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeClicked));
1067
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1068
+ }
1069
+
1070
+ @Override
1071
+ public void onAdCompanions(AdCompanionsEvent adCompanionsEvent) {
1072
+ WritableMap event = Arguments.createMap();
1073
+ event.putString("message", "onAdEvent");
1074
+ event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeCompanion));
1075
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1076
+ }
1077
+
1078
+ @Override
1079
+ public void onAdComplete(AdCompleteEvent adCompleteEvent) {
1080
+ WritableMap event = Arguments.createMap();
1081
+ event.putString("message", "onAdEvent");
1082
+ event.putString("client", adCompleteEvent.getClient().toString());
1083
+ event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeComplete));
1084
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1085
+ }
1086
+
1087
+ @Override
1088
+ public void onAdError(AdErrorEvent adErrorEvent) {
1089
+ WritableMap event = Arguments.createMap();
1090
+ event.putString("message", "onPlayerAdError");
1091
+ event.putInt("code", adErrorEvent.getCode());
1092
+ event.putInt("adErrorCode", adErrorEvent.getAdErrorCode());
1093
+ event.putString("error", adErrorEvent.getMessage());
1094
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topPlayerAdError", event);
1095
+ }
1096
+
1097
+ @Override
1098
+ public void onAdWarning(AdWarningEvent adWarningEvent) {
1099
+ WritableMap event = Arguments.createMap();
1100
+ event.putString("message", "onPlayerAdWarning");
1101
+ event.putInt("code", adWarningEvent.getCode());
1102
+ event.putInt("adErrorCode", adWarningEvent.getAdErrorCode());
1103
+ event.putString("error", adWarningEvent.getMessage());
1104
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topPlayerAdWarning", event);
1105
+ }
1106
+
1107
+ @Override
1108
+ public void onAdImpression(AdImpressionEvent adImpressionEvent) {
1109
+ WritableMap event = Arguments.createMap();
1110
+ event.putString("message", "onAdEvent");
1111
+ event.putString("client", adImpressionEvent.getClient().toString());
1112
+ event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeImpression));
1113
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1114
+ }
1115
+
1116
+ @Override
1117
+ public void onAdMeta(AdMetaEvent adMetaEvent) {
1118
+ WritableMap event = Arguments.createMap();
1119
+ event.putString("message", "onAdEvent");
1120
+ event.putString("client", adMetaEvent.getClient().toString());
1121
+ event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeMeta));
1122
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1123
+ }
1124
+
1125
+ @Override
1126
+ public void onAdRequest(AdRequestEvent adRequestEvent) {
1127
+ WritableMap event = Arguments.createMap();
1128
+ event.putString("message", "onAdEvent");
1129
+ event.putString("client", adRequestEvent.getClient().toString());
1130
+ event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeRequest));
1131
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1132
+ }
1133
+
1134
+ @Override
1135
+ public void onAdSchedule(AdScheduleEvent adScheduleEvent) {
1136
+ WritableMap event = Arguments.createMap();
1137
+ event.putString("message", "onAdEvent");
1138
+ event.putString("client", adScheduleEvent.getClient().toString());
1139
+ event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeSchedule));
1140
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1141
+ }
1142
+
1143
+ @Override
1144
+ public void onAdSkipped(AdSkippedEvent adSkippedEvent) {
1145
+ WritableMap event = Arguments.createMap();
1146
+ event.putString("message", "onAdEvent");
1147
+ event.putString("client", adSkippedEvent.getClient().toString());
1148
+ event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeSkipped));
1149
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1150
+ }
1151
+
1152
+ @Override
1153
+ public void onAdStarted(AdStartedEvent adStartedEvent) {
1154
+ WritableMap event = Arguments.createMap();
1155
+ event.putString("message", "onAdEvent");
1156
+ event.putInt("type", Util.getEventTypeValue(Util.AdEventType.JWAdEventTypeStarted));
1157
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdEvent", event);
1158
+ }
1159
+
1160
+ @Override
1161
+ public void onAdTime(AdTimeEvent adTimeEvent) {
1162
+ WritableMap event = Arguments.createMap();
1163
+ event.putString("message", "onAdTime");
1164
+ event.putDouble("position", adTimeEvent.getPosition());
1165
+ event.putDouble("duration", adTimeEvent.getDuration());
1166
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAdTime", event);
1167
+ }
1168
+
1169
+ @Override
1170
+ public void onAdViewableImpression(AdViewableImpressionEvent adViewableImpressionEvent) {
1171
+ // send everything?
1172
+ }
1173
+
1174
+ @Override
1175
+ public void onBeforeComplete(BeforeCompleteEvent beforeCompleteEvent) {
1176
+ WritableMap event = Arguments.createMap();
1177
+ event.putString("message", "onBeforeComplete");
1178
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topBeforeComplete", event);
1179
+
1180
+ updateWakeLock(false);
1181
+ }
1182
+
1183
+ @Override
1184
+ public void onBeforePlay(BeforePlayEvent beforePlayEvent) {
1185
+ // Ideally done in onFirstFrame instead
1186
+ // if (backgroundAudioEnabled) {
1187
+ // doBindService();
1188
+ // }
1189
+
1190
+ WritableMap event = Arguments.createMap();
1191
+ event.putString("message", "onBeforePlay");
1192
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topBeforePlay", event);
1193
+ }
1194
+
1195
+ // Audio Events
1196
+
1197
+ @Override
1198
+ public void onAudioTracks(AudioTracksEvent audioTracksEvent) {
1199
+ WritableMap event = Arguments.createMap();
1200
+ event.putString("message", "onAudioTracks");
1201
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topAudioTracks", event);
1202
+ }
1203
+
1204
+ @Override
1205
+ public void onAudioTrackChanged(AudioTrackChangedEvent audioTrackChangedEvent) {
1206
+
1207
+ }
1208
+
1209
+ // Player Events
1210
+
1211
+ @Override
1212
+ public void onBuffer(BufferEvent bufferEvent) {
1213
+ WritableMap event = Arguments.createMap();
1214
+ event.putString("message", "onBuffer");
1215
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topBuffer", event);
1216
+
1217
+ updateWakeLock(true);
1218
+ }
1219
+
1220
+ @Override
1221
+ public void onComplete(CompleteEvent completeEvent) {
1222
+ WritableMap event = Arguments.createMap();
1223
+ event.putString("message", "onComplete");
1224
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topComplete", event);
1225
+
1226
+ updateWakeLock(false);
1227
+ }
1228
+
1229
+ @Override
1230
+ public void onControlBarVisibilityChanged(ControlBarVisibilityEvent controlBarVisibilityEvent) {
1231
+ WritableMap event = Arguments.createMap();
1232
+ event.putString("message", "onControlBarVisible");
1233
+ event.putBoolean("visible", controlBarVisibilityEvent.isVisible());
1234
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topControlBarVisible", event);
1235
+
1236
+ updateWakeLock(true);
1237
+ }
1238
+
1239
+ @Override
1240
+ public void onControls(ControlsEvent controlsEvent) {
1241
+
1242
+ }
1243
+
1244
+ @Override
1245
+ public void onDisplayClick(DisplayClickEvent displayClickEvent) {
1246
+
1247
+ }
1248
+
1249
+ @Override
1250
+ public void onError(ErrorEvent errorEvent) {
1251
+ WritableMap event = Arguments.createMap();
1252
+ event.putString("message", "onError");
1253
+ Exception ex = errorEvent.getException();
1254
+ if (ex != null) {
1255
+ event.putString("error", ex.toString());
1256
+ event.putString("description", errorEvent.getMessage());
1257
+ }
1258
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topPlayerError", event);
1259
+
1260
+ updateWakeLock(false);
1261
+ }
1262
+
1263
+ @Override
1264
+ public void onFirstFrame(FirstFrameEvent firstFrameEvent) {
1265
+ if (backgroundAudioEnabled) {
1266
+ doBindService();
1267
+ requestAudioFocus();
1268
+ }
1269
+ }
1270
+
1271
+ @Override
1272
+ public void onFullscreen(FullscreenEvent fullscreenEvent) {
1273
+ if (fullscreenEvent.getFullscreen()) {
1274
+ if (mPlayerView != null) {
1275
+ mPlayerView.requestFocus();
1276
+ }
1277
+
1278
+ WritableMap eventExitFullscreen = Arguments.createMap();
1279
+ eventExitFullscreen.putString("message", "onFullscreen");
1280
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(
1281
+ getId(),
1282
+ "topFullScreen",
1283
+ eventExitFullscreen);
1284
+ } else {
1285
+ WritableMap eventExitFullscreen = Arguments.createMap();
1286
+ eventExitFullscreen.putString("message", "onFullscreenExit");
1287
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(
1288
+ getId(),
1289
+ "topFullScreenExit",
1290
+ eventExitFullscreen);
1291
+ }
1292
+ }
1293
+
1294
+ @Override
1295
+ public void onIdle(IdleEvent idleEvent) {
1296
+
1297
+ }
1298
+
1299
+ @Override
1300
+ public void onPause(PauseEvent pauseEvent) {
1301
+ WritableMap event = Arguments.createMap();
1302
+ event.putString("message", "onPause");
1303
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topPause", event);
1304
+
1305
+ updateWakeLock(false);
1306
+
1307
+ if (!wasInterrupted) {
1308
+ userPaused = true;
1309
+ }
1310
+ }
1311
+
1312
+ @Override
1313
+ public void onPlay(PlayEvent playEvent) {
1314
+ // Ideally done in onFirstFrame instead
1315
+ // if (backgroundAudioEnabled) {
1316
+ // doBindService();
1317
+ // requestAudioFocus();
1318
+ // }
1319
+
1320
+ WritableMap event = Arguments.createMap();
1321
+ event.putString("message", "onPlay");
1322
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topPlay", event);
1323
+
1324
+ updateWakeLock(true);
1325
+
1326
+ userPaused = false;
1327
+ wasInterrupted = false;
1328
+ }
1329
+
1330
+ @Override
1331
+ public void onPlaylistComplete(PlaylistCompleteEvent playlistCompleteEvent) {
1332
+ WritableMap event = Arguments.createMap();
1333
+ event.putString("message", "onPlaylistComplete");
1334
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topPlaylistComplete", event);
1335
+
1336
+ updateWakeLock(false);
1337
+ }
1338
+
1339
+ @Override
1340
+ public void onPlaylistItem(PlaylistItemEvent playlistItemEvent) {
1341
+ // Ideally done in onFirstFrame instead
1342
+ // if (backgroundAudioEnabled) {
1343
+ // doBindService();
1344
+ // }
1345
+
1346
+ currentPlayingIndex = playlistItemEvent.getIndex();
1347
+
1348
+ WritableMap event = Arguments.createMap();
1349
+ event.putString("message", "onPlaylistItem");
1350
+ event.putInt("index", playlistItemEvent.getIndex());
1351
+ Gson gson = new Gson();
1352
+ String json = gson.toJson(playlistItemEvent.getPlaylistItem());
1353
+ event.putString("playlistItem", json);
1354
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topPlaylistItem", event);
1355
+ }
1356
+
1357
+ @Override
1358
+ public void onPlaylist(PlaylistEvent playlistEvent) {
1359
+
1360
+ }
1361
+
1362
+ @Override
1363
+ public void onReady(ReadyEvent readyEvent) {
1364
+ WritableMap event = Arguments.createMap();
1365
+ event.putString("message", "onPlayerReady");
1366
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topOnPlayerReady", event);
1367
+
1368
+ updateWakeLock(true);
1369
+ }
1370
+
1371
+ @Override
1372
+ public void onSeek(SeekEvent seekEvent) {
1373
+ WritableMap event = Arguments.createMap();
1374
+ event.putString("message", "onSeek");
1375
+ event.putDouble("position", seekEvent.getPosition());
1376
+ event.putDouble("offset", seekEvent.getOffset());
1377
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topSeek", event);
1378
+ }
1379
+
1380
+ @Override
1381
+ public void onSeeked(SeekedEvent seekedEvent) {
1382
+ WritableMap event = Arguments.createMap();
1383
+ event.putString("message", "onSeeked");
1384
+ event.putDouble("position", seekedEvent.getPosition());
1385
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topSeeked", event);
1386
+ }
1387
+
1388
+ @Override
1389
+ public void onPlaybackRateChanged(PlaybackRateChangedEvent playbackRateChangedEvent) {
1390
+ WritableMap event = Arguments.createMap();
1391
+ event.putString("message", "onRateChanged");
1392
+ event.putDouble("rate", playbackRateChangedEvent.getPlaybackRate());
1393
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topRateChanged", event);
1394
+ }
1395
+
1396
+ @Override
1397
+ public void onSetupError(SetupErrorEvent setupErrorEvent) {
1398
+ WritableMap event = Arguments.createMap();
1399
+ event.putString("message", "onSetupError");
1400
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topSetupPlayerError", event);
1401
+
1402
+ updateWakeLock(false);
1403
+ }
1404
+
1405
+ @Override
1406
+ public void onTime(TimeEvent timeEvent) {
1407
+ WritableMap event = Arguments.createMap();
1408
+ event.putString("message", "onTime");
1409
+ event.putDouble("position", timeEvent.getPosition());
1410
+ event.putDouble("duration", timeEvent.getDuration());
1411
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topTime", event);
1412
+ }
1413
+
1414
+ @Override
1415
+ public void onCaptionsChanged(CaptionsChangedEvent captionsChangedEvent) {
1416
+
1417
+ }
1418
+
1419
+ @Override
1420
+ public void onCaptionsList(CaptionsListEvent captionsListEvent) {
1421
+
1422
+ }
1423
+
1424
+ @Override
1425
+ public void onMeta(MetaEvent metaEvent) {
1426
+
1427
+ }
1428
+
1429
+ // Picture in Picture events
1430
+
1431
+ @Override
1432
+ public void onPipClose(PipCloseEvent pipCloseEvent) {
1433
+
1434
+ }
1435
+
1436
+ @Override
1437
+ public void onPipOpen(PipOpenEvent pipOpenEvent) {
1438
+
1439
+ }
1440
+
1441
+ // Casting events
1442
+
1443
+ @Override
1444
+ public void onCast(CastEvent castEvent) {
1445
+ WritableMap event = Arguments.createMap();
1446
+ event.putString("message", "onCasting");
1447
+ event.putString("device", castEvent.getDeviceName());
1448
+ event.putBoolean("active", castEvent.isActive());
1449
+ event.putBoolean("available", castEvent.isAvailable());
1450
+ getReactContext().getJSModule(RCTEventEmitter.class).receiveEvent(getId(), "topCasting", event);
1451
+ }
1452
+
1453
+ // LifecycleEventListener
1454
+
1455
+ @Override
1456
+ public void onHostResume() {
1457
+ sessionDepth++;
1458
+ if (sessionDepth == 1) {
1459
+ isInBackground = false;
1460
+ }
1461
+ }
1462
+
1463
+ @Override
1464
+ public void onHostPause() {
1465
+ if (sessionDepth > 0)
1466
+ sessionDepth--;
1467
+ if (sessionDepth == 0) {
1468
+ isInBackground = true;
1469
+ }
1470
+ }
1471
+
1472
+ @Override
1473
+ public void onHostDestroy() {
1474
+ this.destroyPlayer();
1475
+ }
1476
+
1477
+ // utils
1478
+ private final Map<String, Integer> CLIENT_TYPES = MapBuilder.of(
1479
+ "vast", 0,
1480
+ "ima", 1,
1481
+ "ima_dai", 2);
1482
+
1483
+ private final Map<String, UiGroup> GROUP_TYPES = ImmutableMap.<String, UiGroup>builder()
1484
+ .put("overlay", UiGroup.OVERLAY)
1485
+ .put("control_bar", UiGroup.CONTROLBAR)
1486
+ .put("center_controls", UiGroup.CENTER_CONTROLS)
1487
+ .put("next_up", UiGroup.NEXT_UP)
1488
+ .put("error", UiGroup.ERROR)
1489
+ .put("playlist", UiGroup.PLAYLIST)
1490
+ .put("controls_container", UiGroup.PLAYER_CONTROLS_CONTAINER)
1491
+ .put("settings_menu", UiGroup.SETTINGS_MENU)
1492
+ .put("quality_submenu", UiGroup.SETTINGS_QUALITY_SUBMENU)
1493
+ .put("captions_submenu", UiGroup.SETTINGS_CAPTIONS_SUBMENU)
1494
+ .put("playback_submenu", UiGroup.SETTINGS_PLAYBACK_SUBMENU)
1495
+ .put("audiotracks_submenu", UiGroup.SETTINGS_AUDIOTRACKS_SUBMENU)
1496
+ .put("casting_menu", UiGroup.CASTING_MENU).build();
1497
+ }
1498
+
1499
+