@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.
- package/.github/CODEOWNERS +2 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/.github/ISSUE_TEMPLATE/question.md +11 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/LICENSE +21 -0
- package/README.md +425 -0
- package/RNJWPlayer.podspec +44 -0
- package/android/.gradle/8.1.1/checksums/checksums.lock +0 -0
- package/android/.gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock +0 -0
- package/android/.gradle/8.1.1/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/8.1.1/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.1.1/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.1.1/gc.properties +0 -0
- package/android/.gradle/8.2/checksums/checksums.lock +0 -0
- package/android/.gradle/8.2/dependencies-accessors/dependencies-accessors.lock +0 -0
- package/android/.gradle/8.2/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/8.2/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.2/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.2/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
- package/android/.gradle/config.properties +2 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/.idea/gradle.xml +12 -0
- package/android/.idea/migrations.xml +10 -0
- package/android/.idea/misc.xml +10 -0
- package/android/.idea/vcs.xml +6 -0
- package/android/.idea/workspace.xml +54 -0
- package/android/build.gradle +110 -0
- package/android/local.properties +8 -0
- package/android/src/main/AndroidManifest.xml +25 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/ArrayUtil.java +129 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/CastOptionsProvider.java +55 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/MapUtil.java +136 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayer.java +76 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerAds.java +239 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerModule.java +526 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerPackage.java +30 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerView.java +1499 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerViewManager.java +171 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/Util.java +219 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/WidevineCallback.java +62 -0
- package/badges/license.svg +1 -0
- package/badges/version.svg +1 -0
- package/docs/legacy_readme.md +634 -0
- package/docs/props.md +43 -0
- package/docs/types.md +254 -0
- package/index.d.ts +564 -0
- package/index.js +699 -0
- package/ios/RNJWPlayer/RCTConvert+RNJWPlayer.swift +119 -0
- package/ios/RNJWPlayer/RNJWPlayer-Bridging-Header.h +5 -0
- package/ios/RNJWPlayer/RNJWPlayerAds.swift +260 -0
- package/ios/RNJWPlayer/RNJWPlayerModels.swift +149 -0
- package/ios/RNJWPlayer/RNJWPlayerView.swift +1837 -0
- package/ios/RNJWPlayer/RNJWPlayerViewController.swift +616 -0
- package/ios/RNJWPlayer/RNJWPlayerViewManager.m +132 -0
- package/ios/RNJWPlayer/RNJWPlayerViewManager.swift +500 -0
- package/ios/RNJWPlayer.xcodeproj/project.pbxproj +323 -0
- 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
|
+
|