capacitor-plugin-playlist 0.9.0 → 0.9.2
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/android/src/main/java/org/dwbn/plugins/playlist/OnStatusCallback.kt +3 -13
- package/android/src/main/java/org/dwbn/plugins/playlist/PlaylistPlugin.kt +48 -0
- package/android/src/main/java/org/dwbn/plugins/playlist/RmxAudioPlayer.java +9 -0
- package/android/src/test/java/org/dwbn/plugins/playlist/StatusBridgePolicyTest.kt +56 -0
- package/ios/Plugin/Plugin.swift +24 -1
- package/ios/Plugin/RmxAudioPlayer.swift +22 -0
- package/ios/PluginTests/PluginTests.swift +12 -24
- package/package.json +1 -1
- package/android/.gradle/8.11.1/checksums/checksums.lock +0 -0
- package/android/.gradle/8.11.1/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/8.11.1/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/8.11.1/executionHistory/executionHistory.bin +0 -0
- package/android/.gradle/8.11.1/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/8.11.1/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.11.1/fileHashes/fileHashes.bin +0 -0
- package/android/.gradle/8.11.1/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.11.1/gc.properties +0 -0
|
@@ -1,21 +1,11 @@
|
|
|
1
1
|
package org.dwbn.plugins.playlist
|
|
2
2
|
|
|
3
|
-
import android.util.Log
|
|
4
|
-
import com.getcapacitor.JSObject
|
|
5
3
|
import org.json.JSONException
|
|
6
4
|
import org.json.JSONObject
|
|
7
5
|
|
|
8
6
|
class OnStatusCallback internal constructor(private val plugin: PlaylistPlugin) {
|
|
9
7
|
fun onStatus(what: RmxAudioStatusMessage, trackId: String?, param: JSONObject?) {
|
|
10
|
-
|
|
11
|
-
val detail = JSObject()
|
|
12
|
-
detail.put("msgType", what.value)
|
|
13
|
-
detail.put("trackId", trackId)
|
|
14
|
-
detail.put("value", param)
|
|
15
|
-
data.put("action", "status")
|
|
16
|
-
data.put("status", detail)
|
|
17
|
-
Log.v(TAG, "statusChanged:$data")
|
|
18
|
-
plugin.emit("status", data)
|
|
8
|
+
plugin.emitStatus(what, trackId, param)
|
|
19
9
|
}
|
|
20
10
|
|
|
21
11
|
companion object {
|
|
@@ -26,9 +16,9 @@ class OnStatusCallback internal constructor(private val plugin: PlaylistPlugin)
|
|
|
26
16
|
error.put("code", code)
|
|
27
17
|
error.put("message", message ?: "")
|
|
28
18
|
} catch (e: JSONException) {
|
|
29
|
-
Log.e(TAG, "Exception while raising onStatus: ", e)
|
|
19
|
+
android.util.Log.e(TAG, "Exception while raising onStatus: ", e)
|
|
30
20
|
}
|
|
31
21
|
return error
|
|
32
22
|
}
|
|
33
23
|
}
|
|
34
|
-
}
|
|
24
|
+
}
|
|
@@ -17,6 +17,7 @@ public class PlaylistPlugin : Plugin(), OnStatusReportListener {
|
|
|
17
17
|
private var statusCallback: OnStatusCallback? = null
|
|
18
18
|
private var audioPlayerImpl: RmxAudioPlayer? = null
|
|
19
19
|
private var resetStreamOnPause = true
|
|
20
|
+
private var isWebViewActive = true
|
|
20
21
|
|
|
21
22
|
override fun load() {
|
|
22
23
|
audioPlayerImpl = RmxAudioPlayer(this, (this.context.applicationContext as App))
|
|
@@ -422,6 +423,19 @@ public class PlaylistPlugin : Plugin(), OnStatusReportListener {
|
|
|
422
423
|
}
|
|
423
424
|
}
|
|
424
425
|
|
|
426
|
+
override fun handleOnPause() {
|
|
427
|
+
super.handleOnPause()
|
|
428
|
+
isWebViewActive = false
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
override fun handleOnResume() {
|
|
432
|
+
super.handleOnResume()
|
|
433
|
+
isWebViewActive = true
|
|
434
|
+
Handler(Looper.getMainLooper()).post {
|
|
435
|
+
audioPlayerImpl?.emitPlaybackSnapshot()
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
425
439
|
override fun handleOnDestroy() {
|
|
426
440
|
Log.d(TAG, "Plugin destroy")
|
|
427
441
|
super.handleOnDestroy()
|
|
@@ -474,7 +488,41 @@ public class PlaylistPlugin : Plugin(), OnStatusReportListener {
|
|
|
474
488
|
return trackItems
|
|
475
489
|
}
|
|
476
490
|
|
|
491
|
+
fun emitStatus(what: RmxAudioStatusMessage, trackId: String?, param: JSONObject?) {
|
|
492
|
+
if (!shouldEmitStatusToBridge(what, isWebViewActive)) {
|
|
493
|
+
return
|
|
494
|
+
}
|
|
495
|
+
val data = JSObject()
|
|
496
|
+
val detail = JSObject()
|
|
497
|
+
detail.put("msgType", what.value)
|
|
498
|
+
detail.put("trackId", trackId)
|
|
499
|
+
detail.put("value", param)
|
|
500
|
+
data.put("action", "status")
|
|
501
|
+
data.put("status", detail)
|
|
502
|
+
Log.v(TAG, "statusChanged:$data")
|
|
503
|
+
notifyListeners("status", data, shouldRetainStatusEvent(what))
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/** @deprecated Use [emitStatus] so retain/gating policy is applied consistently. */
|
|
477
507
|
fun emit(name: String, data: JSObject) {
|
|
478
508
|
this.notifyListeners(name, data, true)
|
|
479
509
|
}
|
|
510
|
+
|
|
511
|
+
companion object {
|
|
512
|
+
@JvmStatic
|
|
513
|
+
internal fun shouldEmitStatusToBridge(
|
|
514
|
+
what: RmxAudioStatusMessage,
|
|
515
|
+
isWebViewActive: Boolean
|
|
516
|
+
): Boolean {
|
|
517
|
+
if (what == RmxAudioStatusMessage.RMXSTATUS_PLAYBACK_POSITION && !isWebViewActive) {
|
|
518
|
+
return false
|
|
519
|
+
}
|
|
520
|
+
return true
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
@JvmStatic
|
|
524
|
+
internal fun shouldRetainStatusEvent(what: RmxAudioStatusMessage): Boolean {
|
|
525
|
+
return what != RmxAudioStatusMessage.RMXSTATUS_PLAYBACK_POSITION
|
|
526
|
+
}
|
|
527
|
+
}
|
|
480
528
|
}
|
|
@@ -482,4 +482,13 @@ public class RmxAudioPlayer implements PlaybackStatusListener<AudioTrack>,
|
|
|
482
482
|
public float getLastKnownPositionSec() {
|
|
483
483
|
return lastKnownHandoffPositionSec;
|
|
484
484
|
}
|
|
485
|
+
|
|
486
|
+
public void emitPlaybackSnapshot() {
|
|
487
|
+
AudioTrack currentItem = playlistManager.getCurrentItem();
|
|
488
|
+
if (currentItem == null) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
JSONObject trackStatus = getPlayerStatus(currentItem);
|
|
492
|
+
onStatus(RmxAudioStatusMessage.RMXSTATUS_PLAYBACK_POSITION, currentItem.getTrackId(), trackStatus);
|
|
493
|
+
}
|
|
485
494
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
package org.dwbn.plugins.playlist
|
|
2
|
+
|
|
3
|
+
import org.junit.Assert.assertFalse
|
|
4
|
+
import org.junit.Assert.assertTrue
|
|
5
|
+
import org.junit.Test
|
|
6
|
+
|
|
7
|
+
class StatusBridgePolicyTest {
|
|
8
|
+
|
|
9
|
+
@Test
|
|
10
|
+
fun playbackPosition_isSuppressedWhenWebViewInactive() {
|
|
11
|
+
assertFalse(
|
|
12
|
+
PlaylistPlugin.shouldEmitStatusToBridge(
|
|
13
|
+
RmxAudioStatusMessage.RMXSTATUS_PLAYBACK_POSITION,
|
|
14
|
+
isWebViewActive = false
|
|
15
|
+
)
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@Test
|
|
20
|
+
fun playbackPosition_isEmittedWhenWebViewActive() {
|
|
21
|
+
assertTrue(
|
|
22
|
+
PlaylistPlugin.shouldEmitStatusToBridge(
|
|
23
|
+
RmxAudioStatusMessage.RMXSTATUS_PLAYBACK_POSITION,
|
|
24
|
+
isWebViewActive = true
|
|
25
|
+
)
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@Test
|
|
30
|
+
fun playing_isEmittedWhenWebViewInactive() {
|
|
31
|
+
assertTrue(
|
|
32
|
+
PlaylistPlugin.shouldEmitStatusToBridge(
|
|
33
|
+
RmxAudioStatusMessage.RMXSTATUS_PLAYING,
|
|
34
|
+
isWebViewActive = false
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@Test
|
|
40
|
+
fun playbackPosition_isNotRetained() {
|
|
41
|
+
assertFalse(
|
|
42
|
+
PlaylistPlugin.shouldRetainStatusEvent(
|
|
43
|
+
RmxAudioStatusMessage.RMXSTATUS_PLAYBACK_POSITION
|
|
44
|
+
)
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@Test
|
|
49
|
+
fun playing_isRetained() {
|
|
50
|
+
assertTrue(
|
|
51
|
+
PlaylistPlugin.shouldRetainStatusEvent(
|
|
52
|
+
RmxAudioStatusMessage.RMXSTATUS_PLAYING
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
}
|
package/ios/Plugin/Plugin.swift
CHANGED
|
@@ -198,8 +198,31 @@ public class PlaylistPlugin: CAPPlugin, StatusUpdater {
|
|
|
198
198
|
call.resolve(["position": position])
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
+
public override func load() {
|
|
202
|
+
NotificationCenter.default.addObserver(
|
|
203
|
+
self,
|
|
204
|
+
selector: #selector(applicationWillResignActive),
|
|
205
|
+
name: UIApplication.willResignActiveNotification,
|
|
206
|
+
object: nil
|
|
207
|
+
)
|
|
208
|
+
NotificationCenter.default.addObserver(
|
|
209
|
+
self,
|
|
210
|
+
selector: #selector(applicationDidBecomeActive),
|
|
211
|
+
name: UIApplication.didBecomeActiveNotification,
|
|
212
|
+
object: nil
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
@objc private func applicationWillResignActive() {
|
|
217
|
+
audioPlayerImpl.setWebViewActive(false)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
@objc private func applicationDidBecomeActive() {
|
|
221
|
+
audioPlayerImpl.setWebViewActive(true)
|
|
222
|
+
audioPlayerImpl.emitPlaybackSnapshot()
|
|
223
|
+
}
|
|
224
|
+
|
|
201
225
|
// MARK: - StatusUpdater delegate
|
|
202
|
-
// todo: calls to notifyListeners should be throttled
|
|
203
226
|
func onStatus(_ data: [String: Any]) {
|
|
204
227
|
notifyListeners("status", data: data)
|
|
205
228
|
}
|
|
@@ -28,6 +28,7 @@ final class RmxAudioPlayer: NSObject {
|
|
|
28
28
|
private var isReplacingItems = false
|
|
29
29
|
private var isWaitingToStartPlayback = false
|
|
30
30
|
private var loop = false
|
|
31
|
+
private var isWebViewActive = true
|
|
31
32
|
|
|
32
33
|
let avQueuePlayer = AVBidirectionalQueuePlayer(items: [])
|
|
33
34
|
|
|
@@ -1127,6 +1128,10 @@ final class RmxAudioPlayer: NSObject {
|
|
|
1127
1128
|
}
|
|
1128
1129
|
|
|
1129
1130
|
func onStatus(_ what: RmxAudioStatusMessage, trackId: String?, param: [String:Any]?) {
|
|
1131
|
+
if what == .rmxstatus_PLAYBACK_POSITION && !isWebViewActive {
|
|
1132
|
+
return
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1130
1135
|
var status: [String : Any] = [:]
|
|
1131
1136
|
status["msgType"] = NSNumber(value: what.rawValue)
|
|
1132
1137
|
// in the error case contains a dict with "code" and "message", otherwise a NSNumber
|
|
@@ -1217,4 +1222,21 @@ final class RmxAudioPlayer: NSObject {
|
|
|
1217
1222
|
func getLastKnownPosition() -> Float {
|
|
1218
1223
|
lastKnownHandoffPosition
|
|
1219
1224
|
}
|
|
1225
|
+
|
|
1226
|
+
func setWebViewActive(_ active: Bool) {
|
|
1227
|
+
isWebViewActive = active
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
func shouldEmitStatusToBridge(_ what: RmxAudioStatusMessage) -> Bool {
|
|
1231
|
+
if what == .rmxstatus_PLAYBACK_POSITION && !isWebViewActive {
|
|
1232
|
+
return false
|
|
1233
|
+
}
|
|
1234
|
+
return true
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
func emitPlaybackSnapshot() {
|
|
1238
|
+
guard let playerItem = avQueuePlayer.currentAudioTrack else { return }
|
|
1239
|
+
let trackStatus = getStatusItem(playerItem)
|
|
1240
|
+
onStatus(.rmxstatus_PLAYBACK_POSITION, trackId: playerItem.trackId, param: trackStatus)
|
|
1241
|
+
}
|
|
1220
1242
|
}
|
|
@@ -1,35 +1,23 @@
|
|
|
1
1
|
import XCTest
|
|
2
|
-
import Capacitor
|
|
3
2
|
@testable import Plugin
|
|
4
3
|
|
|
5
4
|
class PluginTests: XCTestCase {
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
func testPlaybackPositionSuppressedWhenWebViewInactive() {
|
|
7
|
+
let player = RmxAudioPlayer()
|
|
8
|
+
player.setWebViewActive(false)
|
|
9
|
+
XCTAssertFalse(player.shouldEmitStatusToBridge(.rmxstatus_PLAYBACK_POSITION))
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
func testPlaybackPositionEmittedWhenWebViewActive() {
|
|
13
|
+
let player = RmxAudioPlayer()
|
|
14
|
+
player.setWebViewActive(true)
|
|
15
|
+
XCTAssertTrue(player.shouldEmitStatusToBridge(.rmxstatus_PLAYBACK_POSITION))
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
func
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
let value = "Hello, World!"
|
|
22
|
-
let plugin = MyPlugin()
|
|
23
|
-
|
|
24
|
-
let call = CAPPluginCall(callbackId: "test", options: [
|
|
25
|
-
"value": value
|
|
26
|
-
], success: { (result, _) in
|
|
27
|
-
let resultValue = result!.data["value"] as? String
|
|
28
|
-
XCTAssertEqual(value, resultValue)
|
|
29
|
-
}, error: { (_) in
|
|
30
|
-
XCTFail("Error shouldn't have been called")
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
plugin.echo(call!)
|
|
18
|
+
func testPlayingEmittedWhenWebViewInactive() {
|
|
19
|
+
let player = RmxAudioPlayer()
|
|
20
|
+
player.setWebViewActive(false)
|
|
21
|
+
XCTAssertTrue(player.shouldEmitStatusToBridge(.rmxstatus_PLAYING))
|
|
34
22
|
}
|
|
35
23
|
}
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|