@24i/smartapps-bigscreen-rnv-build-engine 0.17.6-alpha.9 → 0.17.6

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 (57) hide show
  1. package/README.md +16 -12
  2. package/dist/src/constants/buildProductionPackages.js +1 -0
  3. package/dist/src/constants/delopyLivePlatforms.js +2 -1
  4. package/dist/src/constants/platforms.js +2 -0
  5. package/dist/src/engine.js +10 -0
  6. package/dist/src/resolvers/index.js +3 -1
  7. package/dist/src/resolvers/resolveBaseUrl.js +5 -24
  8. package/dist/src/resolvers/resolveProductionZipFileRelativePath.js +1 -2
  9. package/dist/src/resolvers/resolveS3BucketAppPath.js +15 -0
  10. package/dist/src/resolvers/shared/constructFullUrl.js +25 -0
  11. package/dist/src/scripts/buildAllWithSchemes.js +23 -4
  12. package/dist/src/scripts/release/appCenter/deployProductionPackagesToAppCenter.js +20 -10
  13. package/dist/src/scripts/release/urlsMarkdown.js +2 -0
  14. package/dist/src/sdks/index.js +1 -0
  15. package/dist/src/sdks/sdk-androidtv/sdkAndroidtv.js +25 -9
  16. package/dist/src/sdks/sdk-tizen/sdkTizen.js +2 -0
  17. package/dist/src/sdks/sdk-webos/sdkWebos.js +2 -0
  18. package/dist/src/sdks/sdk-webpack/sdkWebpack.js +2 -0
  19. package/dist/src/tasks/deploy/aswS3/deployS3.js +3 -10
  20. package/dist/src/tasks/deploy/aswS3/distToLiveS3.js +4 -5
  21. package/dist/src/tasks/deploy/hbbtv/deployHbbtv.js +1 -1
  22. package/dist/src/tasks/task.rnv.build.js +16 -6
  23. package/dist/src/tasks/task.rnv.configure.js +2 -0
  24. package/dist/src/tasks/task.rnv.deploy.js +2 -0
  25. package/dist/src/tasks/task.rnv.platform.configure.js +33 -1
  26. package/dist/src/tasks/task.rnv.start.js +2 -0
  27. package/dist/src/utils/copyTheoPlayerLibs.js +48 -0
  28. package/dist/src/utils/zipStagingProdBuildsByPlatforms.js +3 -3
  29. package/dist/templates/platforms/androidtv/project/amazoniap/build.gradle +2 -2
  30. package/dist/templates/platforms/androidtv/project/app/build.gradle +17 -21
  31. package/dist/templates/platforms/androidtv/project/app/proguard-rules.pro +15 -0
  32. package/dist/templates/platforms/androidtv/project/app/src/bigscreenAppstage/res/raw/configuration.json +1 -2
  33. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/bridge/BridgeFromJavaScript.kt +4 -58
  34. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/bridge/BridgeToJavaScript.kt +15 -0
  35. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/configuration/BridgeConfig.kt +2 -1
  36. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/di/ActivityModule.kt +0 -3
  37. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/di/ApplicationModule.kt +2 -2
  38. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/di/PerActivity.kt +0 -0
  39. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/PlayerFactoryConfigured.kt +33 -0
  40. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/PlayerFactoryExoPlayerCustomized.kt +7 -1
  41. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/PlayerFactoryTheoPlayerCustomized.kt +14 -0
  42. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/PlayerFactoryVersion.kt +27 -0
  43. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/SourceDrmOverridden.kt +42 -0
  44. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/model/MediaEventType.kt +3 -0
  45. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/parser/SourceParser.kt +89 -0
  46. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/view/Mainview.kt +0 -3
  47. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/view/PlayerCache.kt +2 -2
  48. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/view/WebViewActivity.kt +24 -83
  49. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/viewmodel/WebViewModel.kt +48 -111
  50. package/dist/templates/platforms/androidtv/project/app/src/main/res/layout/activity_web_view.xml +23 -71
  51. package/dist/templates/platforms/androidtv/project/common/build.gradle +2 -2
  52. package/dist/templates/platforms/androidtv/project/googleiap/build.gradle +2 -2
  53. package/package.json +1 -1
  54. package/renative.engine.json +2 -0
  55. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/jump/JumpAnalytics.kt +0 -211
  56. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/parser/ContentModelParser.kt +0 -16
  57. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/parser/DeviceInfoParser.kt +0 -22
@@ -0,0 +1,89 @@
1
+ package com.twentyfouri.tvbridge.webview.parser
2
+
3
+ import com.twentyfouri.player.base.*
4
+ import com.twentyfouri.tvbridge.global.utils.SourceDrmOverridden
5
+ import org.json.JSONException
6
+ import org.json.JSONObject
7
+ import java.net.URI
8
+ import java.util.UUID
9
+
10
+ object SourceParser {
11
+ private val sourceSerializer = DefaultSourceSerializer()
12
+
13
+ fun stringToJson(jsonString: String?): Source? {
14
+ if (jsonString.isNullOrEmpty()) return null
15
+ if (jsonString.startsWith("http://") || jsonString.startsWith("https://")) {
16
+ return Source {
17
+ url = URI(jsonString)
18
+ }
19
+ }
20
+
21
+ try {
22
+ val jsonSource = JSONObject(jsonString)
23
+ if (jsonSource.has("streamUrl")) {
24
+ return parseContentModel(jsonSource)
25
+ }
26
+ return sourceSerializer.toSource(jsonSource)
27
+
28
+ } catch (e: JSONException) {
29
+ return null
30
+ }
31
+ }
32
+
33
+ private fun parseContentModel(jsonSource: JSONObject): Source? {
34
+ return Source {
35
+ val streamUrl = jsonSource.getString("streamUrl", null)
36
+ if (streamUrl.isNullOrEmpty()) return null
37
+ url = URI(streamUrl)
38
+
39
+ mimeType = jsonSource.getString("streamType", null)
40
+ ?.let { MimeType.parse(it) }
41
+
42
+ jsonSource.getObject("drmConfig") { parseDrmModel(it) }
43
+ ?.also { drm.add(it) }
44
+ }
45
+ }
46
+
47
+ private fun parseDrmModel(jsonDrm: JSONObject): SourceDrm? {
48
+ val drmSchemeUuid = jsonDrm.getString("drmSchemeUuid", null)
49
+ val drmLicenseUri = jsonDrm.getString("drmLicenseUrl", null)
50
+ ?.let { URI(it) }
51
+ val drmCustomData = jsonDrm.getObject("drmCustomData") { parseSourceAuthorization (it) }
52
+ val overrideDrmCallback = jsonDrm.getBoolean("overrideDrmCallback")
53
+
54
+ return if (overrideDrmCallback) {
55
+ SourceDrmOverridden {
56
+ packageName = when (drmSchemeUuid) {
57
+ "widevine", WIDEVINE_UUID -> DrmWidevine.packageName
58
+ "playready", PLAYREADY_UUID -> DrmPlayready.packageName
59
+ else -> null
60
+ }
61
+ licenseServer = drmLicenseUri
62
+ authorization = drmCustomData
63
+ }
64
+ } else {
65
+ when (drmSchemeUuid) {
66
+ "widevine", WIDEVINE_UUID -> SourceDrmWidevine {
67
+ licenseServer = drmLicenseUri
68
+ authorization = drmCustomData
69
+ }
70
+ "playready", PLAYREADY_UUID -> SourceDrmPlayready {
71
+ licenseServer = drmLicenseUri
72
+ authorization = drmCustomData
73
+ }
74
+ else -> null
75
+ }
76
+ }
77
+ }
78
+
79
+ private fun parseSourceAuthorization(jsonMap: JSONObject): SourceAuthorization? {
80
+ return SourceAuthorizationHeaders {
81
+ jsonMap.keys().forEach { key ->
82
+ headers[key] = jsonMap.getString(key)
83
+ }
84
+ }
85
+ }
86
+
87
+ val WIDEVINE_UUID = "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"
88
+ val PLAYREADY_UUID = "9a04f079-9840-4286-ab92-e65be0885f95"
89
+ }
@@ -1,7 +1,5 @@
1
1
  package com.twentyfouri.tvbridge.webview.view
2
2
 
3
- import com.twentyfouri.player.base.PlayerBase
4
-
5
3
  /**
6
4
  * Created by destivar on 15/02/16.
7
5
  */
@@ -9,7 +7,6 @@ interface Mainview {
9
7
  fun loadUrl(url: String?)
10
8
  fun goFullscreen()
11
9
  fun exitFullscreen(width: Int, height: Int, left: Int, top: Int)
12
- fun setUrlToView(urlString: String?)
13
10
  fun setBlackCurtainVisibility(visibility: Int)
14
11
  fun showMessage(message: String?)
15
12
  fun requestAudioFocus(): Int
@@ -1,6 +1,6 @@
1
1
  package com.twentyfouri.tvbridge.webview.view
2
2
 
3
- import com.twentyfouri.tvbridge.webview.model.ContentModel
3
+ import com.twentyfouri.player.base.Source
4
4
 
5
5
  class PlayerCache {
6
6
  enum class PlayerState {
@@ -11,5 +11,5 @@ class PlayerCache {
11
11
  var savedPlayerPosition: Double = 0.0
12
12
  var savedPlayerDuration: Double = 0.0
13
13
  var savedPlayerState: PlayerState? = null
14
- var savedContentModel: ContentModel? = null
14
+ var savedSource: Source? = null
15
15
  }
@@ -2,9 +2,6 @@ package com.twentyfouri.tvbridge.webview.view
2
2
 
3
3
  import android.annotation.SuppressLint
4
4
  import android.app.Activity
5
- import android.content.Intent
6
- import android.graphics.Bitmap
7
- import android.graphics.Canvas
8
5
  import android.graphics.Point
9
6
  import android.media.AudioManager
10
7
  import android.media.AudioManager.OnAudioFocusChangeListener
@@ -14,10 +11,9 @@ import android.text.TextWatcher
14
11
  import android.util.Log
15
12
  import android.view.KeyEvent
16
13
  import android.view.View
14
+ import android.view.View.MeasureSpec
17
15
  import android.view.WindowManager
18
16
  import android.view.inputmethod.InputMethodManager
19
- import android.webkit.WebChromeClient
20
- import android.webkit.WebView
21
17
  import android.widget.RelativeLayout
22
18
  import android.widget.Toast
23
19
  import androidx.appcompat.app.AppCompatActivity
@@ -25,7 +21,6 @@ import androidx.databinding.DataBindingUtil
25
21
  import androidx.media.AudioAttributesCompat
26
22
  import androidx.media.AudioFocusRequestCompat
27
23
  import androidx.media.AudioManagerCompat
28
- import com.twentyfouri.tvbridge.BuildConfig
29
24
  import com.twentyfouri.tvbridge.R
30
25
  import com.twentyfouri.tvbridge.configuration.BridgeConfig
31
26
  import com.twentyfouri.tvbridge.databinding.ActivityWebViewBinding
@@ -76,36 +71,14 @@ class WebViewActivity : AppCompatActivity(), Mainview {
76
71
  CookieHandler.setDefault(defaultCookieManager)
77
72
  }
78
73
 
79
- binding = DataBindingUtil.setContentView(this, R.layout.activity_web_view)
80
- binding.viewModel = viewModel
81
- binding.exoplayerView.playerFactory = viewModel.playerFactory
74
+ binding = ActivityWebViewBinding.inflate(layoutInflater)
75
+ setContentView(binding.root)
76
+ binding.playerView.playerFactory = viewModel.playerFactory
82
77
  viewModel.attachView(this)
83
78
  viewModel.configureWebView(binding.webview)
84
- viewModel.player = binding.exoplayerView.player
79
+ viewModel.player = binding.playerView.player
85
80
 
86
- binding.url.addTextChangedListener(object : TextWatcher {
87
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
88
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
89
- viewModel.appUrl = s.toString()
90
- }
91
-
92
- override fun afterTextChanged(s: Editable) {}
93
- })
94
-
95
- val appUrl = config.baseUrl
96
- if (config.customizableUrl) {
97
- viewModel.urlSetterVisible = true
98
- viewModel.appUrl = appUrl
99
- setUrlToView(appUrl)
100
- } else {
101
- viewModel.urlSetterVisible = false
102
- loadUrl(appUrl)
103
- }
104
-
105
- binding.root.viewTreeObserver.addOnGlobalFocusChangeListener { oldFocus: View, newFocus: View ->
106
- Log.v("FOCUS", "global focus changed old = $oldFocus")
107
- Log.v("FOCUS", "global focus changed new = $newFocus")
108
- }
81
+ loadUrl(config.baseUrl)
109
82
 
110
83
  initialized = true
111
84
  }
@@ -170,13 +143,12 @@ class WebViewActivity : AppCompatActivity(), Mainview {
170
143
  public override fun onDestroy() {
171
144
  if (initialized) {
172
145
  viewModel.releasePlayer()
173
- binding.unbind()
174
146
  }
175
147
  super.onDestroy()
176
148
  }
177
149
 
178
150
  override fun goFullscreen() {
179
- val layoutParams = binding.exoplayerView.layoutParams as RelativeLayout.LayoutParams
151
+ val layoutParams = binding.playerView.layoutParams as RelativeLayout.LayoutParams
180
152
  layoutParams.width = -1
181
153
  layoutParams.height = -1
182
154
  layoutParams.leftMargin = 0
@@ -187,8 +159,12 @@ class WebViewActivity : AppCompatActivity(), Mainview {
187
159
  display.getSize(size)
188
160
  val width = size.x
189
161
  val height = size.y
190
- binding.exoplayerView.layoutParams = layoutParams
191
- binding.exoplayerView.layout(width, height, 0, 0)
162
+ binding.playerView.layoutParams = layoutParams
163
+ binding.playerView.measure(
164
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
165
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
166
+ )
167
+ binding.playerView.layout(width, height, 0, 0)
192
168
  }
193
169
 
194
170
  override fun launchIapPurchase(sku: String) {
@@ -196,37 +172,22 @@ class WebViewActivity : AppCompatActivity(), Mainview {
196
172
  }
197
173
 
198
174
  override fun exitFullscreen(width: Int, height: Int, left: Int, top: Int) {
199
- val layoutParams = binding.exoplayerView.layoutParams as RelativeLayout.LayoutParams
175
+ val layoutParams = binding.playerView.layoutParams as RelativeLayout.LayoutParams
200
176
  layoutParams.width = width
201
177
  layoutParams.height = height
202
178
  layoutParams.leftMargin = left
203
179
  layoutParams.topMargin = top
204
180
 
205
181
  //set the layout inner and outer sizes
206
- binding.exoplayerView.layoutParams = layoutParams
207
- binding.exoplayerView.layout(width, height, left, top)
208
- }
209
-
210
- override fun setUrlToView(urlString: String?) {
211
- binding.url.requestFocus()
212
- binding.url.setText(urlString)
213
- binding.url.setSelection(urlString?.length ?: 0)
182
+ binding.playerView.layoutParams = layoutParams
183
+ binding.playerView.layout(width, height, left, top)
214
184
  }
215
185
 
216
186
  override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
217
187
  when (event.keyCode) {
218
- KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_LEFT -> changeFocus()
219
188
  KeyEvent.KEYCODE_DPAD_CENTER -> goToUrl()
220
- KeyEvent.KEYCODE_BACK, KeyEvent.KEYCODE_BUTTON_B, KeyEvent.KEYCODE_BUTTON_A, KeyEvent.KEYCODE_MENU, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_MEDIA_PAUSE, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, KeyEvent.KEYCODE_MEDIA_REWIND -> {
221
- if (!binding.url.hasFocus() && !binding.buttonGo.hasFocus()) {
222
- // Send these key presses to the WebView, through a JavaScript bridge.
223
- viewModel.sendKeyCode(event.keyCode, MediaEventType.KEY_DOWN)
224
- }
225
- }
226
189
  else -> {
227
- if (!binding.url.hasFocus() && !binding.buttonGo.hasFocus()) {
228
- viewModel.sendKeyCode(event.keyCode, MediaEventType.KEY_DOWN)
229
- }
190
+ viewModel.sendKeyCode(event.keyCode, MediaEventType.KEY_DOWN)
230
191
  }
231
192
  }
232
193
  return super.onKeyDown(keyCode, event)
@@ -254,35 +215,19 @@ class WebViewActivity : AppCompatActivity(), Mainview {
254
215
  }
255
216
 
256
217
  private fun goToUrl() {
257
- if (binding.buttonGo.hasFocus()) {
258
- viewModel.onClickGo()
259
- }
260
- }
261
-
262
- private fun changeFocus() {
263
- if (binding.url.hasFocus()) {
264
- binding.buttonGo.requestFocus()
265
- } else if (binding.buttonGo.hasFocus()) {
266
- binding.url.requestFocus()
267
- }
218
+ viewModel.onClickGo()
268
219
  }
269
220
 
270
221
  override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
271
- if (!binding.url.hasFocus() && !binding.buttonGo.hasFocus()) {
272
- // Send these key presses to the WebView, through a JavaScript bridge.
273
- viewModel.sendKeyCode(event.keyCode, MediaEventType.KEY_UP)
274
- return true
275
- }
276
- return super.onKeyUp(keyCode, event)
222
+ // Send these key presses to the WebView, through a JavaScript bridge.
223
+ viewModel.sendKeyCode(event.keyCode, MediaEventType.KEY_UP)
224
+ return true
277
225
  }
278
226
 
279
227
  override fun onKeyLongPress(keyCode: Int, event: KeyEvent): Boolean {
280
- if (!binding.url.hasFocus() && !binding.buttonGo.hasFocus()) {
281
- // Send these key presses to the WebView, through a JavaScript bridge.
282
- viewModel.sendKeyCode(event.keyCode, MediaEventType.KEY_PRESS)
283
- return true
284
- }
285
- return super.onKeyLongPress(keyCode, event)
228
+ // Send these key presses to the WebView, through a JavaScript bridge.
229
+ viewModel.sendKeyCode(event.keyCode, MediaEventType.KEY_PRESS)
230
+ return true
286
231
  }
287
232
 
288
233
  override fun loadUrl(url: String?) {
@@ -294,10 +239,6 @@ class WebViewActivity : AppCompatActivity(), Mainview {
294
239
  }
295
240
  }
296
241
 
297
- override fun onBackPressed() {
298
- super.onBackPressed()
299
- }
300
-
301
242
  companion object {
302
243
  private val defaultCookieManager: CookieManager = CookieManager().apply {
303
244
  setCookiePolicy(CookiePolicy.ACCEPT_ALL)
@@ -5,7 +5,6 @@ import android.content.Context
5
5
  import android.content.Intent
6
6
  import android.graphics.Bitmap
7
7
  import android.graphics.Canvas
8
- import android.net.Uri
9
8
  import android.os.Build
10
9
  import android.util.Log
11
10
  import android.view.KeyEvent
@@ -13,15 +12,9 @@ import android.view.View
13
12
  import android.webkit.CookieManager
14
13
  import android.webkit.WebChromeClient
15
14
  import android.webkit.WebView
16
- import androidx.databinding.BaseObservable
17
- import androidx.databinding.Bindable
18
- import com.google.android.exoplayer2.C
19
- import com.google.android.exoplayer2.SeekParameters
20
15
  import com.google.gson.JsonArray
21
16
  import com.google.gson.JsonObject
22
17
  import com.twentyfouri.player.base.*
23
- import com.twentyfouri.player.exoplayer.PlayerExoPlayer
24
- import com.twentyfouri.tvbridge.BR
25
18
  import com.twentyfouri.tvbridge.BuildConfig
26
19
  import com.twentyfouri.tvbridge.Flavor
27
20
  import com.twentyfouri.tvbridge.bridge.BridgeFromJavaScript
@@ -29,14 +22,12 @@ import com.twentyfouri.tvbridge.bridge.BridgeToJavaScript
29
22
  import com.twentyfouri.tvbridge.common.*
30
23
  import com.twentyfouri.tvbridge.configuration.BridgeConfig
31
24
  import com.twentyfouri.tvbridge.global.utils.LocalStorage
25
+ import com.twentyfouri.tvbridge.global.utils.PlayerFactoryVersion
32
26
  import com.twentyfouri.tvbridge.global.utils.SourceDrmOverridden
33
- import com.twentyfouri.tvbridge.jump.JumpAnalytics
34
27
  import com.twentyfouri.tvbridge.webview.client.BridgeWebView
35
28
  import com.twentyfouri.tvbridge.webview.client.BridgeWebViewClient
36
29
  import com.twentyfouri.tvbridge.webview.client.BridgeWebViewClient.BridgeWebViewClientCallback
37
30
  import com.twentyfouri.tvbridge.webview.model.AnalyticsPlaybackInfo
38
- import com.twentyfouri.tvbridge.webview.model.ContentModel
39
- import com.twentyfouri.tvbridge.webview.model.DrmModel
40
31
  import com.twentyfouri.tvbridge.webview.model.MediaEventType
41
32
  import com.twentyfouri.tvbridge.webview.view.Mainview
42
33
  import com.twentyfouri.tvbridge.webview.view.PlayerCache
@@ -44,7 +35,6 @@ import org.json.JSONArray
44
35
  import org.json.JSONException
45
36
  import org.json.JSONObject
46
37
  import java.net.NetworkInterface
47
- import java.net.URI
48
38
  import javax.inject.Inject
49
39
 
50
40
  /**
@@ -56,7 +46,7 @@ class WebViewModel @Inject constructor(
56
46
  private val config: BridgeConfig,
57
47
  private val iapService: IapService,
58
48
  val playerFactory: PlayerFactoryBase
59
- ) : BaseObservable(), EventListener {
49
+ ) : EventListener {
60
50
  var player: PlayerBase? = null
61
51
  private var view: Mainview? = null
62
52
  private val jsBridge = BridgeToJavaScript(config) { s: String? ->
@@ -64,12 +54,9 @@ class WebViewModel @Inject constructor(
64
54
  }
65
55
  private val iapCallback = InnerIapCallback()
66
56
  private val playerCache = PlayerCache()
67
- private val jumpAnalytics = JumpAnalytics()
68
57
 
69
- private var contentModel: ContentModel? = null
58
+ private var source: Source? = null
70
59
 
71
- val videoTrack: VideoTrack?
72
- get() = player?.selectedVideoTrack
73
60
  val audioTrack: AudioTrack?
74
61
  get() = player?.selectedAudioTrack
75
62
  val subtitleTrack: TextTrack?
@@ -77,17 +64,6 @@ class WebViewModel @Inject constructor(
77
64
 
78
65
  var appUrl: String? = null
79
66
 
80
- var urlSetterVisible: Boolean = false
81
- set(value) {
82
- if (field == value) return
83
- field = value
84
- notifyPropertyChanged(BR.urlSetterVisibility)
85
- }
86
-
87
- @get:Bindable
88
- val urlSetterVisibility: Int
89
- get() = if (urlSetterVisible) View.VISIBLE else View.GONE
90
-
91
67
  fun attachView(view: Mainview?) {
92
68
  this.view = view
93
69
  if (view != null) {
@@ -142,52 +118,42 @@ class WebViewModel @Inject constructor(
142
118
 
143
119
  fun onClickGo() {
144
120
  view?.loadUrl(appUrl)
145
- urlSetterVisible = false
146
121
  if (BuildConfig.DEBUG) {
147
122
  view?.hideKeyboard()
148
123
  }
149
124
  }
150
125
 
151
- fun setVideo(contentModel: ContentModel) {
152
- logContentModel(contentModel)
153
- playDirectly(contentModel)
154
- }
155
-
156
- private fun logContentModel(contentModel: ContentModel) {
157
- Log.i("BridgeVideo", "Url: " + contentModel.streamUrl)
158
- val drmModel = contentModel.drmModel
159
- if (drmModel != null) {
160
- Log.i("BridgeVideo", "DRM: " + drmModel.drmSchemeUuid)
161
- Log.i("BridgeVideo", "LicenseUrl: " + drmModel.drmLicenseUrl)
126
+ fun setVideo(source: Source) {
127
+ var adaptedSource = source
128
+ if (config.drm.shouldOverrideDrmCallback()) {
129
+ adaptedSource = SourceDrmOverridden.replaceSource(adaptedSource)
162
130
  }
131
+ logSource(adaptedSource)
132
+ playDirectly(adaptedSource)
163
133
  }
164
134
 
165
- private fun playInExoPlayerDemoApp(contentModel: ContentModel) {
166
- val intent = Intent("com.google.android.exoplayer.demo.action.VIEW", Uri.parse(contentModel.streamUrl))
167
- val drmModel = contentModel.drmModel
168
- if (drmModel != null) {
169
- intent.putExtra("drm_scheme", drmModel.drmSchemeUuid)
170
- intent.putExtra("drm_license_url", drmModel.drmLicenseUrl)
171
- }
172
- try {
173
- context.startActivity(intent)
174
- } catch (e: Exception) {
175
- Log.w("WebViewModel", "Failed to start ExoPlayer demo app", e)
135
+ private fun logSource(source: Source) {
136
+ Log.i("BridgeVideo", "Url: ${source.url}")
137
+ when (val drmModel = source.drm.firstOrNull()) {
138
+ is SourceDrmWidevine -> {
139
+ Log.i("BridgeVideo", "DRM: " + drmModel.packageName)
140
+ Log.i("BridgeVideo", "LicenseUrl: " + drmModel.licenseServer)
141
+ }
142
+ is SourceDrmPlayready -> {
143
+ Log.i("BridgeVideo", "DRM: " + drmModel.packageName)
144
+ Log.i("BridgeVideo", "LicenseUrl: " + drmModel.licenseServer)
145
+ }
146
+ is SourceDrmOverridden -> {
147
+ Log.i("BridgeVideo", "DRM: " + drmModel.packageName)
148
+ Log.i("BridgeVideo", "LicenseUrl: " + drmModel.licenseServer)
149
+ }
176
150
  }
177
151
  }
178
152
 
179
- private fun playDirectly(contentModel: ContentModel) {
180
- this.contentModel = contentModel
181
- (player as? PlayerExoPlayer)?.exoPlayer?.also { exoPlayer ->
182
- jumpAnalytics.setVideoPlayer(exoPlayer)
183
- exoPlayer.setSeekParameters(SeekParameters.CLOSEST_SYNC)
184
- }
153
+ private fun playDirectly(source: Source) {
154
+ this.source = source
185
155
  player?.also { player ->
186
- player.source = Source {
187
- url = contentModel.streamUrl?.let { URI(it) }
188
- mimeType = detectMimeType(contentModel)
189
- contentModel.drmModel?.let { buildDrm(it) }?.also { drm.add(it) }
190
- }
156
+ player.source = source
191
157
 
192
158
  if (isLowEndDevice) {
193
159
  player.trackRestrictions = player.trackRestrictions.buildUpon {
@@ -207,43 +173,6 @@ class WebViewModel @Inject constructor(
207
173
  }
208
174
  }
209
175
 
210
- private fun detectMimeType(contentModel: ContentModel) =
211
- when (contentModel.streamType) {
212
- null, "" -> null
213
- ".mpd", "mpd", "dash" -> ManifestDash.mimeType
214
- ".ism", "ism", "ss" -> ManifestSmoothStreaming.mimeType
215
- ".m3u8", "m3u8", "hls" -> ManifestHls.mimeType
216
- else -> null
217
- }
218
-
219
- private fun buildDrm(drmModel: DrmModel): SourceDrm? {
220
- val drmScheme = drmModel.drmSchemeUuid
221
- val useOverride = drmModel.overrideDrmCallback ?: config.drm.shouldOverrideDrmCallback()
222
- val useWidevine = drmScheme == "widevine" || drmScheme == C.WIDEVINE_UUID.toString()
223
- val usePlayReady = drmScheme == "playready" || drmScheme == C.PLAYREADY_UUID.toString()
224
- return when {
225
- drmScheme == null -> null
226
- useOverride -> SourceDrmOverridden {
227
- packageName = when {
228
- useWidevine -> DrmWidevine.packageName
229
- usePlayReady -> DrmPlayready.packageName
230
- else -> ""
231
- }
232
- licenseServer = drmModel.drmLicenseUrl?.let { URI(it) }
233
- forceLicenseServer = true
234
- }
235
- useWidevine -> SourceDrmWidevine {
236
- licenseServer = drmModel.drmLicenseUrl?.let { URI(it) }
237
- forceLicenseServer = true
238
- }
239
- usePlayReady -> SourceDrmWidevine {
240
- licenseServer = drmModel.drmLicenseUrl?.let { URI(it) }
241
- forceLicenseServer = true
242
- }
243
- else -> SourceDrmUnrecognized(drmScheme)
244
- }
245
- }
246
-
247
176
  private val isLowEndDevice: Boolean
248
177
  get() = when (Build.MODEL) {
249
178
  "AFTB" -> true
@@ -256,9 +185,9 @@ class WebViewModel @Inject constructor(
256
185
  }
257
186
 
258
187
  fun resumePlayer() {
259
- val savedContentModel = playerCache.savedContentModel
260
- if (playerCache.loadFromCache && savedContentModel != null && playerCache.savedPlayerState !== PlayerCache.PlayerState.PAUSED) {
261
- setVideo(savedContentModel)
188
+ val savedSource = playerCache.savedSource
189
+ if (playerCache.loadFromCache && savedSource != null && playerCache.savedPlayerState !== PlayerCache.PlayerState.PAUSED) {
190
+ setVideo(savedSource)
262
191
  var position = playerCache.savedPlayerPosition
263
192
  val player = this.player ?: return
264
193
  if (player.live) {
@@ -283,26 +212,24 @@ class WebViewModel @Inject constructor(
283
212
 
284
213
  fun stopPlayer() {
285
214
  view?.setBlackCurtainVisibility(View.VISIBLE)
286
- contentModel = null
215
+ source = null
287
216
 
288
217
  player?.also { player ->
289
218
  player.removeEventListener(Event.ALL, this)
290
219
  player.unload()
291
- jumpAnalytics.setVideoPlayer(null)
292
220
  }
293
221
  }
294
222
 
295
223
  fun releasePlayer() {
296
224
  val player = this.player ?: return
297
- if (contentModel != null) {
225
+ if (source != null) {
298
226
  playerCache.loadFromCache = true
299
- playerCache.savedContentModel = contentModel
227
+ playerCache.savedSource = source
300
228
  playerCache.savedPlayerDuration = player.duration
301
229
  playerCache.savedPlayerPosition = player.currentTime
302
230
  playerCache.savedPlayerState = if (player.playing) PlayerCache.PlayerState.PLAYING else PlayerCache.PlayerState.PAUSED
303
231
  }
304
232
  player.unload()
305
- jumpAnalytics.setVideoPlayer(null)
306
233
  }
307
234
 
308
235
  val currentPosition: Double
@@ -317,7 +244,7 @@ class WebViewModel @Inject constructor(
317
244
  val isPlayerPlaying: Boolean
318
245
  get() = player?.playing == true
319
246
  val isInPlayer: Boolean
320
- get() = player != null && contentModel != null
247
+ get() = player != null && source != null
321
248
 
322
249
  fun loadUrl(url: String?) {
323
250
  view?.loadUrl(url)
@@ -359,6 +286,7 @@ class WebViewModel @Inject constructor(
359
286
  }
360
287
  is LoadedMetadataEvent -> {
361
288
  jsBridge.bridgeAndroidToJavaScript_MediaEvent(MediaEventType.LOADEDMETADATA)
289
+ jsBridge.bridgeAndroidToJavaScript_MediaTrackEvent(MediaEventType.TRACKS_CHANGED, player.audioTracks, player.textTracks)
362
290
  }
363
291
  is CanPlayEvent -> {
364
292
  jsBridge.bridgeAndroidToJavaScript_MediaEvent(MediaEventType.CANPLAY)
@@ -389,13 +317,21 @@ class WebViewModel @Inject constructor(
389
317
  jsBridge.bridgeAndroidToJavaScript_MediaEvent(MediaEventType.PAUSE)
390
318
  }
391
319
  }
392
- is LoadedMetadataEvent,
393
320
  is AddAudioTrackEvent, is AddTextTrackEvent,
394
321
  is RemoveAudioTrackEvent, is RemoveTextTrackEvent,
395
322
  is ChangeAudioTrackEvent, is ChangeTextTrackEvent -> {
396
323
  Log.d("WebViewModel", "onTracksChanged: audio=$audioTrack subtitle=$subtitleTrack")
397
324
  jsBridge.bridgeAndroidToJavaScript_MediaTrackEvent(MediaEventType.TRACKS_CHANGED, player.audioTracks, player.textTracks)
398
325
  }
326
+ is AdBreakStartedEvent -> {
327
+ jsBridge.bridgeAndroidToJavaScript_MediaEvent(MediaEventType.AD_BREAK_START)
328
+ }
329
+ is AdBreakEndedEvent -> {
330
+ jsBridge.bridgeAndroidToJavaScript_MediaEvent(MediaEventType.AD_BREAK_END)
331
+ }
332
+ is AdBreaksRescheduledEvent -> {
333
+ jsBridge.bridgeAndroidToJavaScript_MediaAdBreaksEvent(MediaEventType.AD_BREAKS_RESCHEDULED, player.timeline)
334
+ }
399
335
  }
400
336
  }
401
337
 
@@ -424,9 +360,7 @@ class WebViewModel @Inject constructor(
424
360
  }
425
361
 
426
362
  fun setPlaybackInfo(playbackInfo: AnalyticsPlaybackInfo) {
427
- if ("JUMP" == playbackInfo.name) {
428
- jumpAnalytics.setPlaybackInfo(playbackInfo)
429
- }
363
+ // previously used for Jump analytics, not supported with THEO
430
364
  }
431
365
 
432
366
  fun showMessage(message: String?) {
@@ -524,11 +458,14 @@ class WebViewModel @Inject constructor(
524
458
  fun detectDeviceInfo(): JSONObject {
525
459
  val deviceInfo = JSONObject()
526
460
  try {
461
+ val engineVersion = PlayerFactoryVersion.from(playerFactory)
527
462
  deviceInfo.put("deviceBrand", Build.MANUFACTURER)
528
463
  deviceInfo.put("deviceModel", Build.MODEL)
529
464
  deviceInfo.put("osVersion", Build.VERSION.RELEASE)
530
465
  deviceInfo.put("appFlavor", BuildConfig.FLAVOR)
531
466
  deviceInfo.put("appVersion", BuildConfig.VERSION_NAME)
467
+ deviceInfo.put("engineName", engineVersion.engineName)
468
+ deviceInfo.put("engineVersion", engineVersion.engineVersion)
532
469
 
533
470
  val drmKeySystems = mutableSetOf<String>()
534
471
  playerFactory.getSupportedFormats(context).manifest.forEach { manifest ->