expo-video 3.1.0-canary-20251216-3f01dbf → 3.1.0-canary-20251223-b83b31e
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/CHANGELOG.md +1 -0
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/video/FullscreenPlayerActivity.kt +1 -0
- package/android/src/main/java/expo/modules/video/VideoCache.kt +1 -0
- package/android/src/main/java/expo/modules/video/VideoModule.kt +7 -2
- package/android/src/main/java/expo/modules/video/VideoView.kt +51 -74
- package/android/src/main/java/expo/modules/video/delegates/IgnoreSameSet.kt +1 -1
- package/android/src/main/java/expo/modules/video/listeners/VideoManagerListener.kt +10 -0
- package/android/src/main/java/expo/modules/video/{player → listeners}/VideoPlayerListener.kt +3 -2
- package/android/src/main/java/expo/modules/video/listeners/VideoViewListener.kt +13 -0
- package/android/src/main/java/expo/modules/video/{AudioFocusManager.kt → managers/AudioFocusManager.kt} +3 -2
- package/android/src/main/java/expo/modules/video/managers/PictureInPictureManager.kt +329 -0
- package/android/src/main/java/expo/modules/video/{VideoManager.kt → managers/VideoManager.kt} +40 -5
- package/android/src/main/java/expo/modules/video/player/FirstFrameEventGenerator.kt +1 -0
- package/android/src/main/java/expo/modules/video/player/PlayerEvent.kt +1 -0
- package/android/src/main/java/expo/modules/video/player/VideoPlayer.kt +2 -1
- package/android/src/main/java/expo/modules/video/player/VideoPlayerAudioTracks.kt +1 -0
- package/android/src/main/java/expo/modules/video/player/VideoPlayerKeepAwake.kt +1 -1
- package/android/src/main/java/expo/modules/video/player/VideoPlayerSubtitles.kt +1 -0
- package/android/src/main/java/expo/modules/video/records/PiPParams.kt +38 -0
- package/android/src/main/java/expo/modules/video/utils/DataSourceUtils.kt +1 -0
- package/android/src/main/java/expo/modules/video/utils/PictureInPictureHelperFragment.kt +29 -0
- package/android/src/main/java/expo/modules/video/utils/ViewVisibilityUtils.kt +28 -0
- package/expo-module.config.json +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e-sources.jar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e-sources.jar.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e-sources.jar.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e-sources.jar.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e-sources.jar.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e.aar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e.aar.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e.aar.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e.aar.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e.aar.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/{3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf.module → 3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e.module} +22 -22
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e.module.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e.module.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e.module.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e.module.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/{3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf.pom → 3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e.pom} +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e.pom.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e.pom.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e.pom.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251223-b83b31e/expo.modules.video-3.1.0-canary-20251223-b83b31e.pom.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml +4 -4
- package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml.md5 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml.sha1 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml.sha256 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml.sha512 +1 -1
- package/package.json +3 -3
- package/android/src/main/java/expo/modules/video/PictureInPictureHelperFragment.kt +0 -26
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf-sources.jar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf-sources.jar.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf-sources.jar.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf-sources.jar.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf-sources.jar.sha512 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf.aar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf.aar.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf.aar.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf.aar.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf.aar.sha512 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf.module.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf.module.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf.module.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf.module.sha512 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf.pom.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf.pom.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf.pom.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20251216-3f01dbf/expo.modules.video-3.1.0-canary-20251216-3f01dbf.pom.sha512 +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
- [Android] Fix media controls (e.g. bluetooth) not working when `ExpoVideoPlaybackService` is not registered. ([#40728](https://github.com/expo/expo/pull/40728) by [@behenate](https://github.com/behenate))
|
|
17
17
|
- [Web] Fix crash on older versions of Safari. ([#41101](https://github.com/expo/expo/pull/41101) by [@CamWass](https://github.com/CamWass))
|
|
18
18
|
- [Web] Fix video pausing when entering fullscreen in electron apps. ([#40989](https://github.com/expo/expo/pull/40989) by [@behenate](https://github.com/behenate))
|
|
19
|
+
- [Android] Fix crashes when exiting PiP with one than more `VideoView` present on the screen. ([#41090](https://github.com/expo/expo/pull/41090) by [@behenate](https://github.com/behenate))
|
|
19
20
|
|
|
20
21
|
### 💡 Others
|
|
21
22
|
|
package/android/build.gradle
CHANGED
|
@@ -4,13 +4,13 @@ plugins {
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
group = 'host.exp.exponent'
|
|
7
|
-
version = '3.1.0-canary-
|
|
7
|
+
version = '3.1.0-canary-20251223-b83b31e'
|
|
8
8
|
|
|
9
9
|
android {
|
|
10
10
|
namespace "expo.modules.video"
|
|
11
11
|
defaultConfig {
|
|
12
12
|
versionCode 1
|
|
13
|
-
versionName '3.1.0-canary-
|
|
13
|
+
versionName '3.1.0-canary-20251223-b83b31e'
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -22,6 +22,7 @@ import expo.modules.video.utils.applyPiPParams
|
|
|
22
22
|
import expo.modules.video.utils.applyRectHint
|
|
23
23
|
import expo.modules.video.utils.calculatePiPAspectRatio
|
|
24
24
|
import expo.modules.video.utils.calculateRectHint
|
|
25
|
+
import expo.modules.video.managers.VideoManager
|
|
25
26
|
|
|
26
27
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
|
27
28
|
class FullscreenPlayerActivity : Activity() {
|
|
@@ -9,6 +9,7 @@ import androidx.media3.database.StandaloneDatabaseProvider
|
|
|
9
9
|
import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor
|
|
10
10
|
import androidx.media3.datasource.cache.SimpleCache
|
|
11
11
|
import expo.modules.kotlin.exception.Exceptions
|
|
12
|
+
import expo.modules.video.managers.VideoManager
|
|
12
13
|
import java.io.File
|
|
13
14
|
import java.lang.ref.WeakReference
|
|
14
15
|
import java.util.UUID
|
|
@@ -27,6 +27,7 @@ import expo.modules.video.records.SeekTolerance
|
|
|
27
27
|
import expo.modules.video.records.VideoSource
|
|
28
28
|
import expo.modules.video.records.VideoThumbnailOptions
|
|
29
29
|
import expo.modules.video.utils.runWithPiPMisconfigurationSoftHandling
|
|
30
|
+
import expo.modules.video.managers.VideoManager
|
|
30
31
|
import kotlinx.coroutines.async
|
|
31
32
|
import kotlinx.coroutines.awaitAll
|
|
32
33
|
import kotlinx.coroutines.launch
|
|
@@ -43,6 +44,10 @@ class VideoModule : Module() {
|
|
|
43
44
|
VideoManager.onModuleCreated(appContext)
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
OnDestroy {
|
|
48
|
+
VideoManager.onModuleDestroyed(appContext)
|
|
49
|
+
}
|
|
50
|
+
|
|
46
51
|
Function("isPictureInPictureSupported") {
|
|
47
52
|
VideoView.isPictureInPictureSupported(appContext.throwingActivity)
|
|
48
53
|
}
|
|
@@ -396,8 +401,8 @@ private inline fun <reified T : VideoView> ViewDefinitionBuilder<T>.VideoViewCom
|
|
|
396
401
|
Prop("contentFit") { view: T, contentFit: ContentFit ->
|
|
397
402
|
view.contentFit = contentFit
|
|
398
403
|
}
|
|
399
|
-
Prop("startsPictureInPictureAutomatically") { view: T, autoEnterPiP: Boolean ->
|
|
400
|
-
view.autoEnterPiP = autoEnterPiP
|
|
404
|
+
Prop("startsPictureInPictureAutomatically") { view: T, autoEnterPiP: Boolean? ->
|
|
405
|
+
view.autoEnterPiP = autoEnterPiP ?: false
|
|
401
406
|
}
|
|
402
407
|
Prop("allowsFullscreen") { view: T, allowsFullscreen: Boolean? ->
|
|
403
408
|
view.allowsFullscreen = allowsFullscreen ?: true
|
|
@@ -1,22 +1,17 @@
|
|
|
1
1
|
package expo.modules.video
|
|
2
2
|
|
|
3
3
|
import android.app.Activity
|
|
4
|
-
import android.app.PictureInPictureParams
|
|
5
4
|
import android.content.Context
|
|
6
5
|
import android.content.Intent
|
|
7
6
|
import android.graphics.Color
|
|
8
7
|
import android.os.Build
|
|
9
|
-
import android.util.Rational
|
|
10
8
|
import android.view.accessibility.CaptioningManager
|
|
11
9
|
import android.view.LayoutInflater
|
|
12
10
|
import android.view.MotionEvent
|
|
13
11
|
import android.view.View
|
|
14
12
|
import android.view.ViewGroup
|
|
15
|
-
import android.widget.FrameLayout
|
|
16
13
|
import android.widget.ImageButton
|
|
17
|
-
import androidx.fragment.app.FragmentActivity
|
|
18
14
|
import androidx.media3.common.Tracks
|
|
19
|
-
import androidx.media3.common.VideoSize
|
|
20
15
|
import androidx.media3.ui.PlayerView
|
|
21
16
|
import com.facebook.react.bridge.ReactContext
|
|
22
17
|
import com.facebook.react.uimanager.UIManagerHelper
|
|
@@ -28,18 +23,20 @@ import expo.modules.kotlin.views.ExpoView
|
|
|
28
23
|
import expo.modules.video.delegates.IgnoreSameSet
|
|
29
24
|
import expo.modules.video.enums.ContentFit
|
|
30
25
|
import expo.modules.video.player.VideoPlayer
|
|
31
|
-
import expo.modules.video.
|
|
26
|
+
import expo.modules.video.listeners.VideoPlayerListener
|
|
27
|
+
import expo.modules.video.listeners.VideoViewListener
|
|
32
28
|
import expo.modules.video.records.AudioTrack
|
|
33
29
|
import expo.modules.video.records.SubtitleTrack
|
|
34
30
|
import expo.modules.video.records.VideoSource
|
|
35
31
|
import expo.modules.video.records.VideoTrack
|
|
36
|
-
import expo.modules.video.utils.applyPiPParams
|
|
37
32
|
import expo.modules.video.records.FullscreenOptions
|
|
38
33
|
import expo.modules.video.utils.SubtitleUtils
|
|
39
|
-
import expo.modules.video.utils.applyRectHint
|
|
40
|
-
import expo.modules.video.utils.calculatePiPAspectRatio
|
|
41
|
-
import expo.modules.video.utils.calculateRectHint
|
|
42
34
|
import expo.modules.video.utils.dispatchMotionEvent
|
|
35
|
+
import expo.modules.video.managers.VideoManager
|
|
36
|
+
import expo.modules.video.managers.calculateCurrentPipAspectRatio
|
|
37
|
+
import expo.modules.video.records.PiPParams
|
|
38
|
+
import expo.modules.video.utils.calculateRectHint
|
|
39
|
+
import java.lang.ref.WeakReference
|
|
43
40
|
import java.util.UUID
|
|
44
41
|
|
|
45
42
|
class SurfaceVideoView(context: Context, appContext: AppContext) : VideoView(context, appContext)
|
|
@@ -55,8 +52,6 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
|
|
|
55
52
|
val onFullscreenExit by EventDispatcher<Unit>()
|
|
56
53
|
val onFirstFrameRender by EventDispatcher<Unit>()
|
|
57
54
|
|
|
58
|
-
var willEnterPiP: Boolean = false
|
|
59
|
-
|
|
60
55
|
// In some situations we can't detect if the view will enter PiP, in that case the playback will be paused
|
|
61
56
|
// We can get an event after PiP has started, that's when we should resume playback
|
|
62
57
|
var wasAutoPaused: Boolean = false
|
|
@@ -67,13 +62,10 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
|
|
|
67
62
|
var showsAudioTracksButton = false
|
|
68
63
|
private set
|
|
69
64
|
|
|
65
|
+
private var listeners = mutableListOf<WeakReference<VideoViewListener>>()
|
|
70
66
|
private val currentActivity = appContext.throwingActivity
|
|
71
67
|
private val decorView = currentActivity.window.decorView
|
|
72
|
-
private val rootView = decorView.findViewById<ViewGroup>(android.R.id.content)
|
|
73
68
|
private val touchEventCoalescingKeyHelper = TouchEventCoalescingKeyHelper()
|
|
74
|
-
|
|
75
|
-
private val rootViewChildrenOriginalVisibility: ArrayList<Int> = arrayListOf()
|
|
76
|
-
private var pictureInPictureHelperTag: String? = null
|
|
77
69
|
private var reactNativeEventDispatcher: EventDispatcher? = null
|
|
78
70
|
private var captioningChangeListener: CaptioningManager.CaptioningChangeListener? = null
|
|
79
71
|
|
|
@@ -84,6 +76,13 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
|
|
|
84
76
|
}
|
|
85
77
|
}
|
|
86
78
|
|
|
79
|
+
var pipParams by IgnoreSameSet(PiPParams()) { new, old ->
|
|
80
|
+
listeners.forEach {
|
|
81
|
+
it.get()?.onPiPParamsChanged(this, old, new)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
private set
|
|
85
|
+
|
|
87
86
|
// We need to keep track of the target surface view visibility, but only apply it when `useExoShutter` is false.
|
|
88
87
|
var shouldHideSurfaceView: Boolean = true
|
|
89
88
|
|
|
@@ -99,7 +98,7 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
|
|
|
99
98
|
}
|
|
100
99
|
|
|
101
100
|
var autoEnterPiP: Boolean by IgnoreSameSet(false) { new, _ ->
|
|
102
|
-
|
|
101
|
+
pipParams = pipParams.copy(autoEnter = new)
|
|
103
102
|
}
|
|
104
103
|
|
|
105
104
|
var contentFit: ContentFit = ContentFit.CONTAIN
|
|
@@ -217,7 +216,7 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
|
|
|
217
216
|
currentActivity.overridePendingTransition(0, 0)
|
|
218
217
|
}
|
|
219
218
|
onFullscreenEnter(Unit)
|
|
220
|
-
|
|
219
|
+
pipParams = pipParams.copy(blocksAppFromEntering = true)
|
|
221
220
|
}
|
|
222
221
|
|
|
223
222
|
fun attachPlayer() {
|
|
@@ -231,7 +230,7 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
|
|
|
231
230
|
attachPlayer()
|
|
232
231
|
onFullscreenExit(Unit)
|
|
233
232
|
isInFullscreen = false
|
|
234
|
-
|
|
233
|
+
pipParams = pipParams.copy(blocksAppFromEntering = false)
|
|
235
234
|
}
|
|
236
235
|
|
|
237
236
|
fun enterPictureInPicture() {
|
|
@@ -239,49 +238,38 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
|
|
|
239
238
|
throw PictureInPictureUnsupportedException()
|
|
240
239
|
}
|
|
241
240
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
playerView.useController = false
|
|
245
|
-
applyPiPParams(currentActivity, autoEnterPiP, calculateCurrentPipAspectRatio())
|
|
246
|
-
willEnterPiP = true
|
|
247
|
-
|
|
248
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
249
|
-
currentActivity.enterPictureInPictureMode(PictureInPictureParams.Builder().build())
|
|
250
|
-
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
251
|
-
@Suppress("DEPRECATION")
|
|
252
|
-
currentActivity.enterPictureInPictureMode()
|
|
241
|
+
if (playerView.player == null) {
|
|
242
|
+
throw PictureInPictureEnterException("No player attached to the VideoView")
|
|
253
243
|
}
|
|
244
|
+
|
|
245
|
+
pipParams = pipParams.copy(willEnter = true)
|
|
246
|
+
VideoManager.pictureInPicture.enterPictureInPicture(this)
|
|
254
247
|
}
|
|
255
248
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
249
|
+
/**
|
|
250
|
+
* @param pipCandidate - VideoView that was elected to be displayed in PiP
|
|
251
|
+
*/
|
|
252
|
+
fun onStartPictureInPicture(pipCandidate: VideoView?) {
|
|
253
|
+
onPictureInPictureStart(Unit)
|
|
259
254
|
}
|
|
260
255
|
|
|
261
256
|
/**
|
|
262
|
-
*
|
|
263
|
-
* hides all children of the root view and makes the player the only visible child of the rootView.
|
|
257
|
+
* @param pipCandidate - VideoView that was being displayed in PiP
|
|
264
258
|
*/
|
|
265
|
-
fun
|
|
266
|
-
|
|
267
|
-
(
|
|
268
|
-
for (i in 0 until rootView.childCount) {
|
|
269
|
-
if (rootView.getChildAt(i) != playerView) {
|
|
270
|
-
rootViewChildrenOriginalVisibility.add(rootView.getChildAt(i).visibility)
|
|
271
|
-
rootView.getChildAt(i).visibility = View.GONE
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
rootView.addView(playerView, FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT))
|
|
259
|
+
fun onStopPictureInPicture(pipCandidate: VideoView?) {
|
|
260
|
+
pipParams = pipParams.copy(willEnter = false)
|
|
261
|
+
onPictureInPictureStop(Unit)
|
|
275
262
|
}
|
|
276
263
|
|
|
277
|
-
fun
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
for (i in 0 until rootView.childCount) {
|
|
281
|
-
rootView.getChildAt(i).visibility = rootViewChildrenOriginalVisibility[i]
|
|
264
|
+
fun addVideoViewListener(listener: VideoViewListener) {
|
|
265
|
+
if (listeners.any { it.get() == listener }) {
|
|
266
|
+
return
|
|
282
267
|
}
|
|
283
|
-
|
|
284
|
-
|
|
268
|
+
listeners.add(WeakReference(listener))
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
fun removeVideoViewListener(listener: VideoViewListener) {
|
|
272
|
+
listeners.retainAll { it.get() != listener }
|
|
285
273
|
}
|
|
286
274
|
|
|
287
275
|
override fun onVideoSourceLoaded(
|
|
@@ -292,14 +280,16 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
|
|
|
292
280
|
availableSubtitleTracks: List<SubtitleTrack>,
|
|
293
281
|
availableAudioTracks: List<AudioTrack>
|
|
294
282
|
) {
|
|
295
|
-
|
|
296
|
-
val videoSize = VideoSize(it.size.width, it.size.height)
|
|
297
|
-
val aspectRatio = calculatePiPAspectRatio(videoSize, this.width, this.height, contentFit)
|
|
298
|
-
applyPiPParams(currentActivity, autoEnterPiP, aspectRatio)
|
|
299
|
-
}
|
|
283
|
+
pipParams = pipParams.copy(aspectRatio = calculateCurrentPipAspectRatio())
|
|
300
284
|
super.onVideoSourceLoaded(player, videoSource, duration, availableVideoTracks, availableSubtitleTracks, availableAudioTracks)
|
|
301
285
|
}
|
|
302
286
|
|
|
287
|
+
override fun onIsPlayingChanged(player: VideoPlayer, isPlaying: Boolean, oldIsPlaying: Boolean?) {
|
|
288
|
+
if (player == videoPlayer && isPlaying) {
|
|
289
|
+
wasAutoPaused = false
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
303
293
|
override fun onTracksChanged(player: VideoPlayer, tracks: Tracks) {
|
|
304
294
|
showsSubtitlesButton = player.subtitles.availableSubtitleTracks.isNotEmpty()
|
|
305
295
|
showsAudioTracksButton = player.audioTracks.availableAudioTracks.size > 1
|
|
@@ -328,19 +318,13 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
|
|
|
328
318
|
super.onLayout(changed, l, t, r, b)
|
|
329
319
|
// On every re-layout ExoPlayer resets the timeBar to be enabled.
|
|
330
320
|
// We need to disable it to keep scrubbing impossible.
|
|
321
|
+
|
|
322
|
+
pipParams = pipParams.copy(rectHint = calculateRectHint(playerView))
|
|
331
323
|
playerView.setTimeBarInteractive(videoPlayer?.requiresLinearPlayback ?: true)
|
|
332
|
-
applyRectHint(currentActivity, calculateRectHint(playerView))
|
|
333
324
|
}
|
|
334
325
|
|
|
335
326
|
override fun onAttachedToWindow() {
|
|
336
327
|
super.onAttachedToWindow()
|
|
337
|
-
(currentActivity as? FragmentActivity)?.let {
|
|
338
|
-
val fragment = PictureInPictureHelperFragment(this)
|
|
339
|
-
pictureInPictureHelperTag = fragment.id
|
|
340
|
-
it.supportFragmentManager.beginTransaction()
|
|
341
|
-
.add(fragment, fragment.id)
|
|
342
|
-
.commitAllowingStateLoss()
|
|
343
|
-
}
|
|
344
328
|
|
|
345
329
|
// Set up listener for accessibility caption changes when attached to window
|
|
346
330
|
setupCaptioningChangeListener()
|
|
@@ -350,7 +334,7 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
|
|
|
350
334
|
// Set up window focus change listener
|
|
351
335
|
decorView.onFocusChangeListener = windowFocusChangeListener
|
|
352
336
|
|
|
353
|
-
|
|
337
|
+
pipParams = pipParams.copy(canEnter = true)
|
|
354
338
|
}
|
|
355
339
|
|
|
356
340
|
override fun onVisibilityChanged(changedView: View, visibility: Int) {
|
|
@@ -363,13 +347,6 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
|
|
|
363
347
|
|
|
364
348
|
override fun onDetachedFromWindow() {
|
|
365
349
|
super.onDetachedFromWindow()
|
|
366
|
-
(currentActivity as? FragmentActivity)?.let {
|
|
367
|
-
val fragment = it.supportFragmentManager.findFragmentByTag(pictureInPictureHelperTag ?: "")
|
|
368
|
-
?: return
|
|
369
|
-
it.supportFragmentManager.beginTransaction()
|
|
370
|
-
.remove(fragment)
|
|
371
|
-
.commitAllowingStateLoss()
|
|
372
|
-
}
|
|
373
350
|
|
|
374
351
|
// Clean up captioning change listener
|
|
375
352
|
captioningChangeListener?.let {
|
|
@@ -381,7 +358,7 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
|
|
|
381
358
|
// Clean up window focus listener
|
|
382
359
|
decorView.onFocusChangeListener = null
|
|
383
360
|
|
|
384
|
-
|
|
361
|
+
pipParams = pipParams.copy(canEnter = false)
|
|
385
362
|
}
|
|
386
363
|
|
|
387
364
|
// After adding the `PlayerView` to the hierarchy the touch events stop being emitted to the JS side.
|
|
@@ -16,7 +16,7 @@ class IgnoreSameSet<T : Any?>(private var value: T, val propertyMapper: ((T) ->
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
|
19
|
-
if (this.value
|
|
19
|
+
if (this.value?.equals(propertyMapper(value)) ?: false) return
|
|
20
20
|
val oldValue = this.value
|
|
21
21
|
this.value = propertyMapper(value)
|
|
22
22
|
didSet?.invoke(this.value, oldValue)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
package expo.modules.video.listeners
|
|
2
|
+
|
|
3
|
+
import expo.modules.video.VideoView
|
|
4
|
+
|
|
5
|
+
interface VideoManagerListener {
|
|
6
|
+
fun onVideoViewRegistered(videoView: VideoView, allVideoViews: Collection<VideoView>) {}
|
|
7
|
+
fun onVideoViewUnregistered(videoView: VideoView, allVideoViews: Collection<VideoView>) {}
|
|
8
|
+
fun onAppBackgrounded() {}
|
|
9
|
+
fun onAppForegrounded() {}
|
|
10
|
+
}
|
package/android/src/main/java/expo/modules/video/{player → listeners}/VideoPlayerListener.kt
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
package expo.modules.video.
|
|
1
|
+
package expo.modules.video.listeners
|
|
2
2
|
|
|
3
3
|
import androidx.annotation.OptIn
|
|
4
4
|
import androidx.media3.common.TrackSelectionParameters
|
|
@@ -7,11 +7,12 @@ import androidx.media3.common.util.UnstableApi
|
|
|
7
7
|
import expo.modules.video.VideoView
|
|
8
8
|
import expo.modules.video.enums.AudioMixingMode
|
|
9
9
|
import expo.modules.video.enums.PlayerStatus
|
|
10
|
+
import expo.modules.video.player.VideoPlayer
|
|
10
11
|
import expo.modules.video.records.AudioTrack
|
|
11
12
|
import expo.modules.video.records.PlaybackError
|
|
12
13
|
import expo.modules.video.records.SubtitleTrack
|
|
13
|
-
import expo.modules.video.records.VideoSource
|
|
14
14
|
import expo.modules.video.records.TimeUpdate
|
|
15
|
+
import expo.modules.video.records.VideoSource
|
|
15
16
|
import expo.modules.video.records.VideoTrack
|
|
16
17
|
|
|
17
18
|
@OptIn(UnstableApi::class)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
package expo.modules.video.listeners
|
|
2
|
+
|
|
3
|
+
import expo.modules.video.VideoView
|
|
4
|
+
import expo.modules.video.records.PiPParams
|
|
5
|
+
|
|
6
|
+
interface VideoViewListener {
|
|
7
|
+
/**
|
|
8
|
+
* Called when the ability of the view to autoEnterPip has changed.
|
|
9
|
+
* Note: This can be called when `autoEnterPiP` doesn't change, but other factors
|
|
10
|
+
* influence the view's ability to enter PiP.
|
|
11
|
+
*/
|
|
12
|
+
fun onPiPParamsChanged(videoView: VideoView, oldPiPParams: PiPParams, newPiPParams: PiPParams) = Unit
|
|
13
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
package expo.modules.video
|
|
1
|
+
package expo.modules.video.managers
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import android.media.AudioAttributes
|
|
@@ -7,9 +7,10 @@ import android.media.AudioManager
|
|
|
7
7
|
import android.os.Build
|
|
8
8
|
import androidx.media3.common.util.UnstableApi
|
|
9
9
|
import expo.modules.kotlin.AppContext
|
|
10
|
+
import expo.modules.video.FailedToGetAudioFocusManagerException
|
|
10
11
|
import expo.modules.video.enums.AudioMixingMode
|
|
11
12
|
import expo.modules.video.player.VideoPlayer
|
|
12
|
-
import expo.modules.video.
|
|
13
|
+
import expo.modules.video.listeners.VideoPlayerListener
|
|
13
14
|
import kotlinx.coroutines.launch
|
|
14
15
|
import java.lang.ref.WeakReference
|
|
15
16
|
|