@capgo/capacitor-stream-call 0.0.6 → 0.0.19
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/CapgoCapacitorStreamCall.podspec +2 -2
- package/Package.swift +1 -1
- package/README.md +265 -11
- package/android/build.gradle +22 -4
- package/android/src/main/java/ee/forgr/capacitor/streamcall/CustomNotificationHandler.kt +2 -2
- package/android/src/main/java/ee/forgr/capacitor/streamcall/StreamCallPlugin.kt +179 -205
- package/dist/docs.json +761 -12
- package/dist/esm/definitions.d.ts +57 -23
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +2 -1
- package/dist/esm/web.js +58 -22
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +58 -22
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +58 -22
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/StreamCallPlugin/StreamCallPlugin.swift +167 -144
- package/ios/Sources/StreamCallPlugin/TouchInterceptView.swift +3 -3
- package/package.json +2 -2
|
@@ -6,6 +6,8 @@ import android.app.Application
|
|
|
6
6
|
import android.app.KeyguardManager
|
|
7
7
|
import android.content.Context
|
|
8
8
|
import android.graphics.Color
|
|
9
|
+
import android.media.RingtoneManager
|
|
10
|
+
import android.net.Uri
|
|
9
11
|
import android.os.Bundle
|
|
10
12
|
import android.os.Handler
|
|
11
13
|
import android.os.Looper
|
|
@@ -20,31 +22,34 @@ import com.getcapacitor.Plugin
|
|
|
20
22
|
import com.getcapacitor.PluginCall
|
|
21
23
|
import com.getcapacitor.PluginMethod
|
|
22
24
|
import com.getcapacitor.annotation.CapacitorPlugin
|
|
23
|
-
import io.getstream.android.push.firebase.FirebasePushDeviceGenerator
|
|
24
25
|
import io.getstream.android.push.permissions.ActivityLifecycleCallbacks
|
|
25
26
|
import io.getstream.video.android.core.Call
|
|
26
27
|
import io.getstream.video.android.core.GEO
|
|
27
28
|
import io.getstream.video.android.core.StreamVideo
|
|
28
29
|
import io.getstream.video.android.core.StreamVideoBuilder
|
|
29
|
-
import io.getstream.video.android.core.model.RejectReason
|
|
30
30
|
import io.getstream.video.android.core.notifications.NotificationConfig
|
|
31
31
|
import io.getstream.video.android.core.notifications.NotificationHandler
|
|
32
|
-
import io.getstream.video.android.core.sounds.emptyRingingConfig
|
|
33
32
|
import io.getstream.video.android.core.sounds.toSounds
|
|
34
33
|
import io.getstream.video.android.model.StreamCallId
|
|
35
34
|
import io.getstream.video.android.model.User
|
|
36
35
|
import io.getstream.video.android.model.streamCallId
|
|
37
36
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
|
38
|
-
import kotlinx.coroutines.flow.Flow
|
|
39
37
|
import kotlinx.coroutines.launch
|
|
40
|
-
import org.openapitools.client.models.CallAcceptedEvent
|
|
41
|
-
import org.openapitools.client.models.CallEndedEvent
|
|
42
|
-
import org.openapitools.client.models.CallMissedEvent
|
|
43
|
-
import org.openapitools.client.models.CallRejectedEvent
|
|
44
|
-
import org.openapitools.client.models.CallSessionEndedEvent
|
|
45
|
-
import org.openapitools.client.models.VideoEvent
|
|
46
38
|
import io.getstream.video.android.model.Device
|
|
47
|
-
import kotlinx.coroutines.
|
|
39
|
+
import kotlinx.coroutines.tasks.await
|
|
40
|
+
import com.google.firebase.messaging.FirebaseMessaging
|
|
41
|
+
import io.getstream.android.push.PushProvider
|
|
42
|
+
import io.getstream.android.push.firebase.FirebasePushDeviceGenerator
|
|
43
|
+
import io.getstream.android.video.generated.models.CallAcceptedEvent
|
|
44
|
+
import io.getstream.android.video.generated.models.CallCreatedEvent
|
|
45
|
+
import io.getstream.android.video.generated.models.CallEndedEvent
|
|
46
|
+
import io.getstream.android.video.generated.models.CallMissedEvent
|
|
47
|
+
import io.getstream.android.video.generated.models.CallRejectedEvent
|
|
48
|
+
import io.getstream.android.video.generated.models.CallRingEvent
|
|
49
|
+
import io.getstream.android.video.generated.models.CallSessionEndedEvent
|
|
50
|
+
import io.getstream.android.video.generated.models.CallSessionStartedEvent
|
|
51
|
+
import io.getstream.android.video.generated.models.VideoEvent
|
|
52
|
+
import io.getstream.video.android.core.sounds.RingingConfig
|
|
48
53
|
|
|
49
54
|
// I am not a religious pearson, but at this point, I am not sure even god himself would understand this code
|
|
50
55
|
// It's a spaghetti-like, tangled, unreadable mess and frankly, I am deeply sorry for the code crimes commited in the Android impl
|
|
@@ -63,7 +68,12 @@ public class StreamCallPlugin : Plugin() {
|
|
|
63
68
|
private var savedActivity: Activity? = null
|
|
64
69
|
private var savedActivityPaused = false
|
|
65
70
|
private var savedCallsToEndOnResume = mutableListOf<Call>()
|
|
66
|
-
private val callStates: MutableMap<String,
|
|
71
|
+
private val callStates: MutableMap<String, LocalCallState> = mutableMapOf()
|
|
72
|
+
|
|
73
|
+
// Store current call info
|
|
74
|
+
private var currentCallId: String = ""
|
|
75
|
+
private var currentCallType: String = ""
|
|
76
|
+
private var currentCallState: String = ""
|
|
67
77
|
|
|
68
78
|
private enum class State {
|
|
69
79
|
NOT_INITIALIZED,
|
|
@@ -71,6 +81,11 @@ public class StreamCallPlugin : Plugin() {
|
|
|
71
81
|
INITIALIZED
|
|
72
82
|
}
|
|
73
83
|
|
|
84
|
+
public fun incomingOnlyRingingConfig(): RingingConfig = object : RingingConfig {
|
|
85
|
+
override val incomingCallSoundUri: Uri? = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
|
|
86
|
+
override val outgoingCallSoundUri: Uri? = null
|
|
87
|
+
}
|
|
88
|
+
|
|
74
89
|
private fun runOnMainThread(action: () -> Unit) {
|
|
75
90
|
mainHandler.post { action() }
|
|
76
91
|
}
|
|
@@ -170,7 +185,7 @@ public class StreamCallPlugin : Plugin() {
|
|
|
170
185
|
declineCall(declinedCall)
|
|
171
186
|
},
|
|
172
187
|
onAcceptCall = { acceptedCall ->
|
|
173
|
-
|
|
188
|
+
internalAcceptCall(acceptedCall)
|
|
174
189
|
},
|
|
175
190
|
onHideIncomingCall = {
|
|
176
191
|
hideIncomingCall()
|
|
@@ -192,7 +207,7 @@ public class StreamCallPlugin : Plugin() {
|
|
|
192
207
|
val call = streamVideoClient?.call(id = cid.id, type = cid.type)
|
|
193
208
|
kotlinx.coroutines.GlobalScope.launch {
|
|
194
209
|
call?.get()
|
|
195
|
-
call?.let {
|
|
210
|
+
call?.let { internalAcceptCall(it) }
|
|
196
211
|
}
|
|
197
212
|
}
|
|
198
213
|
}
|
|
@@ -211,12 +226,8 @@ public class StreamCallPlugin : Plugin() {
|
|
|
211
226
|
// Stop ringtone
|
|
212
227
|
ringtonePlayer?.stopRinging()
|
|
213
228
|
|
|
214
|
-
// Notify that call has ended
|
|
215
|
-
|
|
216
|
-
put("callId", call.id)
|
|
217
|
-
put("state", "rejected")
|
|
218
|
-
}
|
|
219
|
-
notifyListeners("callEvent", data)
|
|
229
|
+
// Notify that call has ended using our helper
|
|
230
|
+
updateCallStatusAndNotify(call.id, "rejected")
|
|
220
231
|
|
|
221
232
|
hideIncomingCall()
|
|
222
233
|
} catch (e: Exception) {
|
|
@@ -250,14 +261,6 @@ public class StreamCallPlugin : Plugin() {
|
|
|
250
261
|
}
|
|
251
262
|
}
|
|
252
263
|
|
|
253
|
-
// private fun remoteIncomingCallNotif() {
|
|
254
|
-
// CallService.removeIncomingCall(
|
|
255
|
-
// context,
|
|
256
|
-
// StreamCallId.fromCallCid(call.cid),
|
|
257
|
-
// StreamVideo.instance().state.callConfigRegistry.get(call.type),
|
|
258
|
-
// )
|
|
259
|
-
// }
|
|
260
|
-
|
|
261
264
|
private fun setupViews() {
|
|
262
265
|
val context = context
|
|
263
266
|
val parent = bridge?.webView?.parent as? ViewGroup ?: return
|
|
@@ -468,16 +471,17 @@ public class StreamCallPlugin : Plugin() {
|
|
|
468
471
|
)
|
|
469
472
|
|
|
470
473
|
val notificationConfig = NotificationConfig(
|
|
471
|
-
pushDeviceGenerators = listOf(
|
|
474
|
+
pushDeviceGenerators = listOf(
|
|
475
|
+
FirebasePushDeviceGenerator(
|
|
472
476
|
providerName = "firebase",
|
|
473
477
|
context = contextToUse
|
|
474
|
-
)
|
|
478
|
+
)
|
|
479
|
+
),
|
|
475
480
|
requestPermissionOnAppLaunch = { true },
|
|
476
481
|
notificationHandler = notificationHandler,
|
|
477
482
|
)
|
|
478
483
|
|
|
479
|
-
val soundsConfig =
|
|
480
|
-
soundsConfig.incomingCallSoundUri
|
|
484
|
+
val soundsConfig = incomingOnlyRingingConfig()
|
|
481
485
|
// Initialize StreamVideo client
|
|
482
486
|
streamVideoClient = StreamVideoBuilder(
|
|
483
487
|
context = contextToUse,
|
|
@@ -561,62 +565,41 @@ public class StreamCallPlugin : Plugin() {
|
|
|
561
565
|
client.subscribe { event: VideoEvent ->
|
|
562
566
|
android.util.Log.v("StreamCallPlugin", "Received an event ${event.getEventType()} $event")
|
|
563
567
|
when (event) {
|
|
568
|
+
is CallRingEvent -> {
|
|
569
|
+
updateCallStatusAndNotify(event.callCid, "ringing")
|
|
570
|
+
}
|
|
564
571
|
// Handle CallCreatedEvent differently - only log it but don't try to access members yet
|
|
565
|
-
is
|
|
566
|
-
val callCid = event.
|
|
572
|
+
is CallCreatedEvent -> {
|
|
573
|
+
val callCid = event.callCid
|
|
567
574
|
android.util.Log.d("StreamCallPlugin", "Call created: $callCid")
|
|
568
575
|
|
|
569
576
|
// let's get the members
|
|
570
|
-
val callParticipants = event.members.filter{ it.user.id != this@StreamCallPlugin.streamVideoClient?.userId }
|
|
577
|
+
val callParticipants = event.members.filter{ it.user.id != this@StreamCallPlugin.streamVideoClient?.userId }.map { it.user.id }
|
|
571
578
|
android.util.Log.d("StreamCallPlugin", "Call created for $callCid with ${callParticipants.size} participants")
|
|
572
579
|
|
|
573
580
|
// Start tracking this call now that we have the member list
|
|
574
581
|
startCallTimeoutMonitor(callCid, callParticipants)
|
|
575
582
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
}
|
|
580
|
-
notifyListeners("callEvent", data)
|
|
583
|
+
// Use direction from event if available
|
|
584
|
+
val callType = callCid.split(":").firstOrNull() ?: "default"
|
|
585
|
+
updateCallStatusAndNotify(callCid, "created")
|
|
581
586
|
}
|
|
582
587
|
// Add handler for CallSessionStartedEvent which contains participant information
|
|
583
|
-
is
|
|
584
|
-
val callCid = event.
|
|
585
|
-
|
|
586
|
-
val data = JSObject().apply {
|
|
587
|
-
put("callId", callCid)
|
|
588
|
-
put("state", "session_started")
|
|
589
|
-
}
|
|
590
|
-
notifyListeners("callEvent", data)
|
|
588
|
+
is CallSessionStartedEvent -> {
|
|
589
|
+
val callCid = event.callCid
|
|
590
|
+
updateCallStatusAndNotify(callCid, "session_started")
|
|
591
591
|
}
|
|
592
592
|
|
|
593
593
|
is CallRejectedEvent -> {
|
|
594
594
|
val userId = event.user.id
|
|
595
|
-
val callCid = event.
|
|
595
|
+
val callCid = event.callCid
|
|
596
596
|
|
|
597
597
|
// Update call state
|
|
598
598
|
callStates[callCid]?.let { callState ->
|
|
599
599
|
callState.participantResponses[userId] = "rejected"
|
|
600
600
|
}
|
|
601
601
|
|
|
602
|
-
|
|
603
|
-
// android.util.Log.d("StreamCallPlugin", "Setting overlay invisible due to CallRejectedEvent for call ${event.call.cid}")
|
|
604
|
-
// overlayView?.setContent {
|
|
605
|
-
// CallOverlayView(
|
|
606
|
-
// context = context,
|
|
607
|
-
// streamVideo = streamVideoClient,
|
|
608
|
-
// call = null
|
|
609
|
-
// )
|
|
610
|
-
// }
|
|
611
|
-
// overlayView?.isVisible = false
|
|
612
|
-
// }
|
|
613
|
-
|
|
614
|
-
val data = JSObject().apply {
|
|
615
|
-
put("callId", event.call.cid)
|
|
616
|
-
put("state", "rejected")
|
|
617
|
-
put("userId", userId)
|
|
618
|
-
}
|
|
619
|
-
notifyListeners("callEvent", data)
|
|
602
|
+
updateCallStatusAndNotify(callCid, "rejected", userId)
|
|
620
603
|
|
|
621
604
|
// Check if all participants have responded
|
|
622
605
|
checkAllParticipantsResponded(callCid)
|
|
@@ -624,7 +607,7 @@ public class StreamCallPlugin : Plugin() {
|
|
|
624
607
|
|
|
625
608
|
is CallMissedEvent -> {
|
|
626
609
|
val userId = event.user.id
|
|
627
|
-
val callCid = event.
|
|
610
|
+
val callCid = event.callCid
|
|
628
611
|
|
|
629
612
|
// Update call state
|
|
630
613
|
callStates[callCid]?.let { callState ->
|
|
@@ -638,12 +621,7 @@ public class StreamCallPlugin : Plugin() {
|
|
|
638
621
|
moveAllActivitiesToBackgroundOrKill(context)
|
|
639
622
|
}
|
|
640
623
|
|
|
641
|
-
|
|
642
|
-
put("callId", callCid)
|
|
643
|
-
put("state", "missed")
|
|
644
|
-
put("userId", userId)
|
|
645
|
-
}
|
|
646
|
-
notifyListeners("callEvent", data)
|
|
624
|
+
updateCallStatusAndNotify(callCid, "missed", userId)
|
|
647
625
|
|
|
648
626
|
// Check if all participants have responded
|
|
649
627
|
checkAllParticipantsResponded(callCid)
|
|
@@ -651,7 +629,7 @@ public class StreamCallPlugin : Plugin() {
|
|
|
651
629
|
|
|
652
630
|
is CallAcceptedEvent -> {
|
|
653
631
|
val userId = event.user.id
|
|
654
|
-
val callCid = event.
|
|
632
|
+
val callCid = event.callCid
|
|
655
633
|
|
|
656
634
|
// Update call state
|
|
657
635
|
callStates[callCid]?.let { callState ->
|
|
@@ -663,48 +641,34 @@ public class StreamCallPlugin : Plugin() {
|
|
|
663
641
|
callState.timer = null
|
|
664
642
|
}
|
|
665
643
|
|
|
666
|
-
|
|
667
|
-
put("callId", callCid)
|
|
668
|
-
put("state", "accepted")
|
|
669
|
-
put("userId", userId)
|
|
670
|
-
}
|
|
671
|
-
notifyListeners("callEvent", data)
|
|
644
|
+
updateCallStatusAndNotify(callCid, "accepted", userId)
|
|
672
645
|
}
|
|
673
646
|
|
|
674
647
|
is CallEndedEvent -> {
|
|
675
648
|
runOnMainThread {
|
|
676
|
-
android.util.Log.d("StreamCallPlugin", "Setting overlay invisible due to CallEndedEvent for call ${event.
|
|
649
|
+
android.util.Log.d("StreamCallPlugin", "Setting overlay invisible due to CallEndedEvent for call ${event.callCid}")
|
|
677
650
|
// Clean up call resources
|
|
678
|
-
val callCid = event.
|
|
651
|
+
val callCid = event.callCid
|
|
679
652
|
cleanupCall(callCid)
|
|
680
653
|
}
|
|
681
|
-
|
|
682
|
-
put("callId", event.call.cid)
|
|
683
|
-
put("state", "left")
|
|
684
|
-
}
|
|
685
|
-
notifyListeners("callEvent", data)
|
|
654
|
+
updateCallStatusAndNotify(event.callCid, "left")
|
|
686
655
|
}
|
|
687
656
|
|
|
688
657
|
is CallSessionEndedEvent -> {
|
|
689
658
|
runOnMainThread {
|
|
690
|
-
android.util.Log.d("StreamCallPlugin", "Setting overlay invisible due to CallSessionEndedEvent for call ${event.call.
|
|
659
|
+
android.util.Log.d("StreamCallPlugin", "Setting overlay invisible due to CallSessionEndedEvent for call ${event.callCid}. Test session: ${event.call.session?.endedAt}")
|
|
691
660
|
// Clean up call resources
|
|
692
|
-
val callCid = event.
|
|
661
|
+
val callCid = event.callCid
|
|
693
662
|
cleanupCall(callCid)
|
|
694
663
|
}
|
|
695
|
-
|
|
696
|
-
put("callId", event.call.cid)
|
|
697
|
-
put("state", "left")
|
|
698
|
-
}
|
|
699
|
-
notifyListeners("callEvent", data)
|
|
664
|
+
updateCallStatusAndNotify(event.callCid, "left")
|
|
700
665
|
}
|
|
701
666
|
|
|
702
667
|
else -> {
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
notifyListeners("callEvent", data)
|
|
668
|
+
updateCallStatusAndNotify(
|
|
669
|
+
streamVideoClient?.state?.activeCall?.value?.cid ?: "",
|
|
670
|
+
event.getEventType()
|
|
671
|
+
)
|
|
708
672
|
}
|
|
709
673
|
}
|
|
710
674
|
}
|
|
@@ -721,19 +685,11 @@ public class StreamCallPlugin : Plugin() {
|
|
|
721
685
|
android.util.Log.d("StreamCallPlugin", "- All participants: ${state.participants}")
|
|
722
686
|
android.util.Log.d("StreamCallPlugin", "- Remote participants: ${state.remoteParticipants}")
|
|
723
687
|
|
|
724
|
-
// Notify that a call has started
|
|
725
|
-
|
|
726
|
-
put("callId", call.cid)
|
|
727
|
-
put("state", "joined")
|
|
728
|
-
}
|
|
729
|
-
notifyListeners("callEvent", data)
|
|
688
|
+
// Notify that a call has started using our helper
|
|
689
|
+
updateCallStatusAndNotify(call.cid, "joined")
|
|
730
690
|
} ?: run {
|
|
731
|
-
// Notify that call has ended
|
|
732
|
-
|
|
733
|
-
put("callId", "")
|
|
734
|
-
put("state", "left")
|
|
735
|
-
}
|
|
736
|
-
notifyListeners("callEvent", data)
|
|
691
|
+
// Notify that call has ended using our helper
|
|
692
|
+
updateCallStatusAndNotify("", "left")
|
|
737
693
|
}
|
|
738
694
|
}
|
|
739
695
|
}
|
|
@@ -791,8 +747,42 @@ public class StreamCallPlugin : Plugin() {
|
|
|
791
747
|
})
|
|
792
748
|
}
|
|
793
749
|
|
|
750
|
+
@PluginMethod
|
|
751
|
+
public fun acceptCall(call: PluginCall) {
|
|
752
|
+
try {
|
|
753
|
+
val streamVideoCall = streamVideoClient?.state?.ringingCall?.value
|
|
754
|
+
if (streamVideoCall == null) {
|
|
755
|
+
call.reject("Ringing call is null")
|
|
756
|
+
return
|
|
757
|
+
}
|
|
758
|
+
kotlinx.coroutines.GlobalScope.launch {
|
|
759
|
+
internalAcceptCall(streamVideoCall)
|
|
760
|
+
}
|
|
761
|
+
} catch (t: Throwable) {
|
|
762
|
+
android.util.Log.d("StreamCallPlugin", "JS -> acceptCall fail", t);
|
|
763
|
+
call.reject("Cannot acceptCall")
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
@PluginMethod
|
|
768
|
+
public fun rejectCall(call: PluginCall) {
|
|
769
|
+
try {
|
|
770
|
+
val streamVideoCall = streamVideoClient?.state?.ringingCall?.value
|
|
771
|
+
if (streamVideoCall == null) {
|
|
772
|
+
call.reject("Ringing call is null")
|
|
773
|
+
return
|
|
774
|
+
}
|
|
775
|
+
kotlinx.coroutines.GlobalScope.launch {
|
|
776
|
+
declineCall(streamVideoCall)
|
|
777
|
+
}
|
|
778
|
+
} catch (t: Throwable) {
|
|
779
|
+
android.util.Log.d("StreamCallPlugin", "JS -> rejectCall fail", t);
|
|
780
|
+
call.reject("Cannot rejectCall")
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
794
784
|
@OptIn(DelicateCoroutinesApi::class)
|
|
795
|
-
private fun
|
|
785
|
+
private fun internalAcceptCall(call: Call) {
|
|
796
786
|
kotlinx.coroutines.GlobalScope.launch {
|
|
797
787
|
try {
|
|
798
788
|
// Stop ringtone
|
|
@@ -807,12 +797,8 @@ public class StreamCallPlugin : Plugin() {
|
|
|
807
797
|
// Join the call without affecting others
|
|
808
798
|
call.accept()
|
|
809
799
|
|
|
810
|
-
// Notify that call has started
|
|
811
|
-
|
|
812
|
-
put("callId", call.id)
|
|
813
|
-
put("state", "joined")
|
|
814
|
-
}
|
|
815
|
-
notifyListeners("callEvent", data)
|
|
800
|
+
// Notify that call has started using helper
|
|
801
|
+
updateCallStatusAndNotify(call.id, "joined")
|
|
816
802
|
|
|
817
803
|
// Show overlay view with the active call
|
|
818
804
|
runOnMainThread {
|
|
@@ -935,7 +921,6 @@ public class StreamCallPlugin : Plugin() {
|
|
|
935
921
|
val callId = call.id
|
|
936
922
|
android.util.Log.d("StreamCallPlugin", "Attempting to end call $callId")
|
|
937
923
|
call.leave()
|
|
938
|
-
call.reject(reason = RejectReason.Cancel)
|
|
939
924
|
|
|
940
925
|
// Capture context from the overlayView
|
|
941
926
|
val currentContext = overlayView?.context ?: this.savedContext
|
|
@@ -988,12 +973,8 @@ public class StreamCallPlugin : Plugin() {
|
|
|
988
973
|
incomingCallView?.isVisible = false
|
|
989
974
|
}
|
|
990
975
|
|
|
991
|
-
// Notify that call has ended
|
|
992
|
-
|
|
993
|
-
put("callId", callId)
|
|
994
|
-
put("state", "left")
|
|
995
|
-
}
|
|
996
|
-
notifyListeners("callEvent", data)
|
|
976
|
+
// Notify that call has ended using helper
|
|
977
|
+
updateCallStatusAndNotify(callId, "left")
|
|
997
978
|
}
|
|
998
979
|
|
|
999
980
|
@OptIn(DelicateCoroutinesApi::class)
|
|
@@ -1079,7 +1060,7 @@ public class StreamCallPlugin : Plugin() {
|
|
|
1079
1060
|
val callType = call.getString("type") ?: "default"
|
|
1080
1061
|
val shouldRing = call.getBoolean("ring") ?: true
|
|
1081
1062
|
val callId = java.util.UUID.randomUUID().toString()
|
|
1082
|
-
val
|
|
1063
|
+
val team = call.getString("team");
|
|
1083
1064
|
|
|
1084
1065
|
android.util.Log.d("StreamCallPlugin", "Creating call:")
|
|
1085
1066
|
android.util.Log.d("StreamCallPlugin", "- Call ID: $callId")
|
|
@@ -1098,15 +1079,23 @@ public class StreamCallPlugin : Plugin() {
|
|
|
1098
1079
|
|
|
1099
1080
|
android.util.Log.d("StreamCallPlugin", "Creating call with members...")
|
|
1100
1081
|
// Create the call with all members
|
|
1101
|
-
streamCall?.create(
|
|
1082
|
+
val createResult = streamCall?.create(
|
|
1102
1083
|
memberIds = userIds + selfUserId,
|
|
1103
1084
|
custom = emptyMap(),
|
|
1104
|
-
ring = shouldRing
|
|
1085
|
+
ring = shouldRing,
|
|
1086
|
+
team = team,
|
|
1105
1087
|
)
|
|
1088
|
+
|
|
1089
|
+
if (createResult?.isFailure == true) {
|
|
1090
|
+
throw (createResult.errorOrNull() ?: RuntimeException("Unknown error creating call")) as Throwable
|
|
1091
|
+
}
|
|
1106
1092
|
|
|
1107
1093
|
android.util.Log.d("StreamCallPlugin", "Setting overlay visible for outgoing call $callId")
|
|
1108
1094
|
// Show overlay view
|
|
1109
1095
|
activity?.runOnUiThread {
|
|
1096
|
+
streamCall?.microphone?.setEnabled(true)
|
|
1097
|
+
streamCall?.camera?.setEnabled(true)
|
|
1098
|
+
|
|
1110
1099
|
overlayView?.setContent {
|
|
1111
1100
|
CallOverlayView(
|
|
1112
1101
|
context = context,
|
|
@@ -1132,7 +1121,7 @@ public class StreamCallPlugin : Plugin() {
|
|
|
1132
1121
|
}
|
|
1133
1122
|
|
|
1134
1123
|
private fun startCallTimeoutMonitor(callCid: String, memberIds: List<String>) {
|
|
1135
|
-
val callState =
|
|
1124
|
+
val callState = LocalCallState(members = memberIds)
|
|
1136
1125
|
|
|
1137
1126
|
val handler = Handler(Looper.getMainLooper())
|
|
1138
1127
|
val timeoutRunnable = object : Runnable {
|
|
@@ -1172,12 +1161,7 @@ public class StreamCallPlugin : Plugin() {
|
|
|
1172
1161
|
if (memberId !in callState.participantResponses) {
|
|
1173
1162
|
callState.participantResponses[memberId] = "missed"
|
|
1174
1163
|
|
|
1175
|
-
|
|
1176
|
-
put("callId", callCid)
|
|
1177
|
-
put("state", "missed")
|
|
1178
|
-
put("userId", memberId)
|
|
1179
|
-
}
|
|
1180
|
-
notifyListeners("callEvent", data)
|
|
1164
|
+
updateCallStatusAndNotify(callCid, "missed", memberId)
|
|
1181
1165
|
}
|
|
1182
1166
|
}
|
|
1183
1167
|
|
|
@@ -1195,13 +1179,8 @@ public class StreamCallPlugin : Plugin() {
|
|
|
1195
1179
|
// Clean up state - we don't need to do this in endCallRaw because we already did it here
|
|
1196
1180
|
callStates.remove(callCid)
|
|
1197
1181
|
|
|
1198
|
-
// Notify that call has ended
|
|
1199
|
-
|
|
1200
|
-
put("callId", callCid)
|
|
1201
|
-
put("state", "ended")
|
|
1202
|
-
put("reason", "timeout")
|
|
1203
|
-
}
|
|
1204
|
-
notifyListeners("callEvent", data)
|
|
1182
|
+
// Notify that call has ended using helper
|
|
1183
|
+
updateCallStatusAndNotify(callCid, "ended", null, "timeout")
|
|
1205
1184
|
} catch (e: Exception) {
|
|
1206
1185
|
android.util.Log.e("StreamCallPlugin", "Error ending timed out call", e)
|
|
1207
1186
|
}
|
|
@@ -1271,13 +1250,8 @@ public class StreamCallPlugin : Plugin() {
|
|
|
1271
1250
|
// Clean up state - we don't need to do this in endCallRaw because we already did it here
|
|
1272
1251
|
callStates.remove(callCid)
|
|
1273
1252
|
|
|
1274
|
-
// Notify that call has ended
|
|
1275
|
-
|
|
1276
|
-
put("callId", callCid)
|
|
1277
|
-
put("state", "ended")
|
|
1278
|
-
put("reason", "all_rejected_or_missed")
|
|
1279
|
-
}
|
|
1280
|
-
notifyListeners("callEvent", data)
|
|
1253
|
+
// Notify that call has ended using helper
|
|
1254
|
+
updateCallStatusAndNotify(callCid, "ended", null, "all_rejected_or_missed")
|
|
1281
1255
|
} catch (e: Exception) {
|
|
1282
1256
|
android.util.Log.e("StreamCallPlugin", "Error ending call after all rejected/missed", e)
|
|
1283
1257
|
}
|
|
@@ -1289,68 +1263,68 @@ public class StreamCallPlugin : Plugin() {
|
|
|
1289
1263
|
|
|
1290
1264
|
private suspend fun magicDeviceDelete(streamVideoClient: StreamVideo) {
|
|
1291
1265
|
try {
|
|
1292
|
-
android.util.Log.d("StreamCallPlugin", "Starting magicDeviceDelete
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
android.util.Log.e("StreamCallPlugin", "streamNotificationManager is null")
|
|
1302
|
-
return
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
|
-
android.util.Log.d("StreamCallPlugin", "Successfully accessed streamNotificationManager")
|
|
1306
|
-
|
|
1307
|
-
// Get deviceTokenStorage from notification manager
|
|
1308
|
-
val notificationManagerClass = notificationManager.javaClass
|
|
1309
|
-
val deviceTokenStorageField = notificationManagerClass.getDeclaredField("deviceTokenStorage")
|
|
1310
|
-
deviceTokenStorageField.isAccessible = true
|
|
1311
|
-
val deviceTokenStorage = deviceTokenStorageField.get(notificationManager)
|
|
1312
|
-
|
|
1313
|
-
if (deviceTokenStorage == null) {
|
|
1314
|
-
android.util.Log.e("StreamCallPlugin", "deviceTokenStorage is null")
|
|
1315
|
-
return
|
|
1316
|
-
}
|
|
1317
|
-
|
|
1318
|
-
android.util.Log.d("StreamCallPlugin", "Successfully accessed deviceTokenStorage")
|
|
1319
|
-
|
|
1320
|
-
// Access the DeviceTokenStorage object dynamically without hardcoding class
|
|
1321
|
-
val deviceTokenStorageClass = deviceTokenStorage.javaClass
|
|
1322
|
-
|
|
1323
|
-
// Get the userDevice Flow from deviceTokenStorage
|
|
1324
|
-
val userDeviceField = deviceTokenStorageClass.getDeclaredField("userDevice")
|
|
1325
|
-
userDeviceField.isAccessible = true
|
|
1326
|
-
val userDeviceFlow = userDeviceField.get(deviceTokenStorage)
|
|
1327
|
-
|
|
1328
|
-
if (userDeviceFlow == null) {
|
|
1329
|
-
android.util.Log.e("StreamCallPlugin", "userDevice Flow is null")
|
|
1330
|
-
return
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
android.util.Log.d("StreamCallPlugin", "Successfully accessed userDevice Flow: $userDeviceFlow")
|
|
1266
|
+
android.util.Log.d("StreamCallPlugin", "Starting magicDeviceDelete operation")
|
|
1267
|
+
|
|
1268
|
+
FirebaseMessaging.getInstance().token.await()?.let {
|
|
1269
|
+
android.util.Log.d("StreamCallPlugin", "Found firebase token")
|
|
1270
|
+
val device = Device(
|
|
1271
|
+
id = it,
|
|
1272
|
+
pushProvider = PushProvider.FIREBASE.key,
|
|
1273
|
+
pushProviderName = "firebase",
|
|
1274
|
+
)
|
|
1334
1275
|
|
|
1335
|
-
|
|
1336
|
-
try {
|
|
1337
|
-
castedUserDeviceFlow.first {
|
|
1338
|
-
if (it == null) {
|
|
1339
|
-
android.util.Log.d("StreamCallPlugin", "Device is null. Nothing to remove")
|
|
1340
|
-
return@first true;
|
|
1341
|
-
}
|
|
1342
|
-
streamVideoClient.deleteDevice(it)
|
|
1343
|
-
return@first true;
|
|
1344
|
-
}
|
|
1345
|
-
} catch (e: Throwable) {
|
|
1346
|
-
android.util.Log.e("StreamCallPlugin", "Cannot collect flow in magicDeviceDelete", e)
|
|
1276
|
+
streamVideoClient.deleteDevice(device)
|
|
1347
1277
|
}
|
|
1348
1278
|
} catch (e: Exception) {
|
|
1349
1279
|
android.util.Log.e("StreamCallPlugin", "Error in magicDeviceDelete", e)
|
|
1350
1280
|
}
|
|
1351
1281
|
}
|
|
1352
1282
|
|
|
1353
|
-
|
|
1283
|
+
@PluginMethod
|
|
1284
|
+
fun getCallStatus(call: PluginCall) {
|
|
1285
|
+
// If not in a call, reject
|
|
1286
|
+
if (currentCallId.isEmpty() || currentCallState == "left") {
|
|
1287
|
+
call.reject("Not in a call")
|
|
1288
|
+
return
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
val result = JSObject()
|
|
1292
|
+
result.put("callId", currentCallId)
|
|
1293
|
+
result.put("state", currentCallState)
|
|
1294
|
+
|
|
1295
|
+
// No additional fields to ensure compatibility with CallEvent interface
|
|
1296
|
+
|
|
1297
|
+
call.resolve(result)
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
// Helper method to update call status and notify listeners
|
|
1301
|
+
private fun updateCallStatusAndNotify(callId: String, state: String, userId: String? = null, reason: String? = null) {
|
|
1302
|
+
// Update stored call info
|
|
1303
|
+
currentCallId = callId
|
|
1304
|
+
currentCallState = state
|
|
1305
|
+
|
|
1306
|
+
// Get call type from call ID if available
|
|
1307
|
+
if (callId.contains(":")) {
|
|
1308
|
+
currentCallType = callId.split(":").firstOrNull() ?: ""
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
// Create data object with only the fields in the CallEvent interface
|
|
1312
|
+
val data = JSObject().apply {
|
|
1313
|
+
put("callId", callId)
|
|
1314
|
+
put("state", state)
|
|
1315
|
+
userId?.let {
|
|
1316
|
+
put("userId", it)
|
|
1317
|
+
}
|
|
1318
|
+
reason?.let {
|
|
1319
|
+
put("reason", it)
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
// Notify listeners
|
|
1324
|
+
notifyListeners("callEvent", data)
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
data class LocalCallState(
|
|
1354
1328
|
val members: List<String>,
|
|
1355
1329
|
val participantResponses: MutableMap<String, String> = mutableMapOf(),
|
|
1356
1330
|
val createdAt: Long = System.currentTimeMillis(),
|