@stream-io/react-native-callingx 0.1.0-beta.7 → 0.1.1-beta.1
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/build.gradle +7 -1
- package/android/src/main/AndroidManifest.xml +31 -1
- package/android/src/main/java/io/getstream/rn/callingx/CallEventBroadcastReceiver.kt +17 -0
- package/android/src/main/java/io/getstream/rn/callingx/CallRegistrationStore.kt +145 -0
- package/android/src/main/java/io/getstream/rn/callingx/CallService.kt +301 -83
- package/android/src/main/java/io/getstream/rn/callingx/CallingxModuleImpl.kt +148 -390
- package/android/src/main/java/io/getstream/rn/callingx/StreamMessagingService.kt +48 -0
- package/android/src/main/java/io/getstream/rn/callingx/model/Call.kt +1 -0
- package/android/src/main/java/io/getstream/rn/callingx/notifications/CallNotificationManager.kt +188 -48
- package/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationIntentFactory.kt +14 -8
- package/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationReceiverActivity.kt +12 -1
- package/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationReceiverService.kt +7 -0
- package/android/src/main/java/io/getstream/rn/callingx/repo/CallRepository.kt +38 -19
- package/android/src/main/java/io/getstream/rn/callingx/repo/LegacyCallRepository.kt +64 -55
- package/android/src/main/java/io/getstream/rn/callingx/repo/TelecomCallRepository.kt +241 -195
- package/android/src/main/java/io/getstream/rn/callingx/utils/CallEventBus.kt +61 -0
- package/android/src/main/java/io/getstream/rn/callingx/utils/SettingsStore.kt +51 -0
- package/android/src/newarch/java/io/getstream/rn/callingx/CallingxModule.kt +12 -3
- package/android/src/oldarch/java/io/getstream/rn/callingx/CallingxModule.kt +13 -3
- package/dist/module/CallingxModule.js +20 -24
- package/dist/module/CallingxModule.js.map +1 -1
- package/dist/module/spec/NativeCallingx.js.map +1 -1
- package/dist/module/utils/constants.js +24 -14
- package/dist/module/utils/constants.js.map +1 -1
- package/dist/typescript/src/CallingxModule.d.ts +4 -2
- package/dist/typescript/src/CallingxModule.d.ts.map +1 -1
- package/dist/typescript/src/spec/NativeCallingx.d.ts +7 -4
- package/dist/typescript/src/spec/NativeCallingx.d.ts.map +1 -1
- package/dist/typescript/src/types.d.ts +33 -5
- package/dist/typescript/src/types.d.ts.map +1 -1
- package/dist/typescript/src/utils/constants.d.ts +2 -3
- package/dist/typescript/src/utils/constants.d.ts.map +1 -1
- package/ios/AudioSessionManager.swift +2 -2
- package/ios/Callingx.mm +41 -17
- package/ios/CallingxImpl.swift +213 -83
- package/ios/Settings.swift +2 -2
- package/ios/UUIDStorage.swift +10 -10
- package/ios/VoipNotificationsManager.swift +8 -8
- package/package.json +4 -2
- package/src/CallingxModule.ts +20 -21
- package/src/spec/NativeCallingx.ts +10 -6
- package/src/types.ts +36 -4
- package/src/utils/constants.ts +23 -12
- /package/android/src/main/java/io/getstream/rn/callingx/{ResourceUtils.kt → utils/ResourceUtils.kt} +0 -0
- /package/android/src/main/java/io/getstream/rn/callingx/{Utils.kt → utils/Utils.kt} +0 -0
package/android/build.gradle
CHANGED
|
@@ -65,7 +65,7 @@ android {
|
|
|
65
65
|
"generated/java",
|
|
66
66
|
"generated/jni",
|
|
67
67
|
"build/generated/source/codegen/java",
|
|
68
|
-
"build/generated/source/codegen/jni"
|
|
68
|
+
"build/generated/source/codegen/jni",
|
|
69
69
|
]
|
|
70
70
|
if (isNewArchitectureEnabled()) {
|
|
71
71
|
java.srcDirs += ["src/newarch"]
|
|
@@ -87,4 +87,10 @@ dependencies {
|
|
|
87
87
|
implementation "com.facebook.react:react-android"
|
|
88
88
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
89
89
|
implementation "androidx.core:core-telecom:1.0.1"
|
|
90
|
+
// Compile-time only dependency so StreamMessagingService can reference RemoteMessage.
|
|
91
|
+
// The consuming app (via @react-native-firebase/messaging) must provide the actual runtime version.
|
|
92
|
+
compileOnly "com.google.firebase:firebase-messaging-ktx:24.1.2"
|
|
93
|
+
// Optional: use Firebase native code when the app has react-native-firebase installed (peer deps)
|
|
94
|
+
implementation project(':react-native-firebase_app')
|
|
95
|
+
implementation project(':react-native-firebase_messaging')
|
|
90
96
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
xmlns:tools="http://schemas.android.com/tools">
|
|
2
3
|
|
|
3
4
|
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
|
|
4
5
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
@@ -25,5 +26,34 @@
|
|
|
25
26
|
android:foregroundServiceType="phoneCall"
|
|
26
27
|
android:stopWithTask="true" />
|
|
27
28
|
|
|
29
|
+
<service
|
|
30
|
+
android:name="io.getstream.rn.callingx.StreamMessagingService"
|
|
31
|
+
android:exported="false">
|
|
32
|
+
<intent-filter>
|
|
33
|
+
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
|
34
|
+
</intent-filter>
|
|
35
|
+
</service>
|
|
36
|
+
|
|
37
|
+
<!-- Action values must match constants in CallingxModuleImpl.kt -->
|
|
38
|
+
<receiver
|
|
39
|
+
android:name="io.getstream.rn.callingx.CallEventBroadcastReceiver"
|
|
40
|
+
android:exported="false">
|
|
41
|
+
<intent-filter>
|
|
42
|
+
<action android:name="io.getstream.CALL_REGISTERED" />
|
|
43
|
+
<action android:name="io.getstream.CALL_REGISTERED_INCOMING" />
|
|
44
|
+
<action android:name="io.getstream.CALL_ANSWERED" />
|
|
45
|
+
<action android:name="io.getstream.CALL_INACTIVE" />
|
|
46
|
+
<action android:name="io.getstream.CALL_ACTIVE" />
|
|
47
|
+
<action android:name="io.getstream.CALL_MUTED" />
|
|
48
|
+
<action android:name="io.getstream.CALL_ENDPOINT_CHANGED" />
|
|
49
|
+
<action android:name="io.getstream.CALL_END" />
|
|
50
|
+
<action android:name="io.getstream.CALL_REGISTRATION_FAILED" />
|
|
51
|
+
</intent-filter>
|
|
52
|
+
</receiver>
|
|
53
|
+
|
|
54
|
+
<!-- Remove default FCM service so StreamMessagingService is the single handler -->
|
|
55
|
+
<service
|
|
56
|
+
android:name="io.invertase.firebase.messaging.ReactNativeFirebaseMessagingService"
|
|
57
|
+
tools:node="remove" />
|
|
28
58
|
</application>
|
|
29
59
|
</manifest>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
package io.getstream.rn.callingx
|
|
2
|
+
|
|
3
|
+
import android.content.BroadcastReceiver
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.content.Intent
|
|
6
|
+
import android.os.Bundle
|
|
7
|
+
|
|
8
|
+
class CallEventBroadcastReceiver : BroadcastReceiver() {
|
|
9
|
+
|
|
10
|
+
override fun onReceive(context: Context, intent: Intent) {
|
|
11
|
+
val action = intent.action ?: return
|
|
12
|
+
val extras = intent.extras ?: Bundle()
|
|
13
|
+
|
|
14
|
+
CallEventBus.publish(CallEvent(action = action, extras = extras))
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
package io.getstream.rn.callingx
|
|
2
|
+
|
|
3
|
+
import android.os.Handler
|
|
4
|
+
import android.os.Looper
|
|
5
|
+
import com.facebook.react.bridge.Promise
|
|
6
|
+
import io.getstream.rn.callingx.model.CallAction
|
|
7
|
+
import java.util.Collections
|
|
8
|
+
import java.util.concurrent.ConcurrentHashMap
|
|
9
|
+
import kotlin.collections.emptyList
|
|
10
|
+
|
|
11
|
+
object CallRegistrationStore {
|
|
12
|
+
|
|
13
|
+
private const val TAG = "[Callingx] CallRegistrationStore"
|
|
14
|
+
private const val DISPLAY_TIMEOUT_MS = 10_000L
|
|
15
|
+
|
|
16
|
+
private val trackedCallIds: MutableSet<String> = ConcurrentHashMap.newKeySet()
|
|
17
|
+
|
|
18
|
+
/** Pending actions per callId, queued until the call is registered in Telecom. */
|
|
19
|
+
private val pendingActionsByCallId = ConcurrentHashMap<String, MutableList<CallAction>>()
|
|
20
|
+
|
|
21
|
+
// Per-callId pending promises for displayIncomingCall awaiting CALL_REGISTERED_INCOMING_ACTION
|
|
22
|
+
private val pendingPromises = mutableMapOf<String, Promise>()
|
|
23
|
+
private val pendingTimeouts = mutableMapOf<String, Runnable>()
|
|
24
|
+
private val mainHandler = Handler(Looper.getMainLooper())
|
|
25
|
+
|
|
26
|
+
fun trackCallRegistration(callId: String, promise: Promise?) {
|
|
27
|
+
debugLog(
|
|
28
|
+
TAG,
|
|
29
|
+
"[store] trackCallRegistration: Tracking call registration for callId: $callId"
|
|
30
|
+
)
|
|
31
|
+
trackedCallIds.add(callId)
|
|
32
|
+
|
|
33
|
+
if (promise == null) return
|
|
34
|
+
|
|
35
|
+
synchronized(pendingPromises) {
|
|
36
|
+
// Cancel any existing timeout for this callId to avoid a stale runnable
|
|
37
|
+
// rejecting the new promise after it overwrites the old one.
|
|
38
|
+
pendingTimeouts.remove(callId)?.let { mainHandler.removeCallbacks(it) }
|
|
39
|
+
|
|
40
|
+
pendingPromises[callId] = promise
|
|
41
|
+
|
|
42
|
+
val timeoutRunnable = Runnable {
|
|
43
|
+
synchronized(pendingPromises) {
|
|
44
|
+
pendingPromises
|
|
45
|
+
.remove(callId)
|
|
46
|
+
?.reject("TIMEOUT", "Timed out waiting for call registration: $callId")
|
|
47
|
+
pendingTimeouts.remove(callId)
|
|
48
|
+
trackedCallIds.remove(callId)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
pendingTimeouts[callId] = timeoutRunnable
|
|
52
|
+
mainHandler.postDelayed(timeoutRunnable, DISPLAY_TIMEOUT_MS)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
fun onRegistrationSuccess(callId: String) {
|
|
57
|
+
synchronized(pendingPromises) {
|
|
58
|
+
pendingTimeouts.remove(callId)?.let { mainHandler.removeCallbacks(it) }
|
|
59
|
+
pendingPromises.remove(callId)?.resolve(true)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
fun onRegistrationFailed(callId: String) {
|
|
64
|
+
reportRegistrationFail(
|
|
65
|
+
callId,
|
|
66
|
+
"REGISTRATION_FAILED",
|
|
67
|
+
"Failed to register call with telecom: $callId",
|
|
68
|
+
null
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
fun reportRegistrationFail(
|
|
73
|
+
callId: String,
|
|
74
|
+
code: String,
|
|
75
|
+
message: String?,
|
|
76
|
+
throwable: Throwable?
|
|
77
|
+
) {
|
|
78
|
+
trackedCallIds.remove(callId)
|
|
79
|
+
|
|
80
|
+
synchronized(pendingPromises) {
|
|
81
|
+
pendingTimeouts.remove(callId)?.let { mainHandler.removeCallbacks(it) }
|
|
82
|
+
val promise = pendingPromises.remove(callId)
|
|
83
|
+
pendingActionsByCallId.remove(callId)
|
|
84
|
+
if (promise != null) {
|
|
85
|
+
if (throwable != null) {
|
|
86
|
+
promise.reject(code, message, throwable)
|
|
87
|
+
} else if (message != null) {
|
|
88
|
+
promise.reject(code, message)
|
|
89
|
+
} else {
|
|
90
|
+
promise.reject(code, "Unknown error")
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
fun addTrackedCall(callId: String) {
|
|
97
|
+
debugLog(TAG, "[store] addTrackedCall: Adding tracked call: $callId")
|
|
98
|
+
trackedCallIds.add(callId)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
fun removeTrackedCall(callId: String) {
|
|
102
|
+
debugLog(TAG, "[store] removeTrackedCall: Removing tracked call: $callId")
|
|
103
|
+
trackedCallIds.remove(callId)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
fun isCallTracked(callId: String): Boolean {
|
|
107
|
+
val isTracked = trackedCallIds.contains(callId)
|
|
108
|
+
debugLog(TAG, "[store] isCallTracked: Is call $callId tracked: $isTracked")
|
|
109
|
+
return isTracked
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
fun hasRegisteredCall(): Boolean {
|
|
113
|
+
return trackedCallIds.isNotEmpty()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Queues an action for a call that is not yet registered.
|
|
118
|
+
* Pending actions are drained and executed once registration completes.
|
|
119
|
+
*/
|
|
120
|
+
fun addPendingAction(callId: String, action: CallAction) {
|
|
121
|
+
debugLog(TAG, "[store] addPendingAction: callId=$callId action=${action::class.simpleName}")
|
|
122
|
+
pendingActionsByCallId
|
|
123
|
+
.computeIfAbsent(callId) { Collections.synchronizedList(mutableListOf()) }
|
|
124
|
+
.add(action)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Returns and removes all queued actions for this call.
|
|
129
|
+
* Used once a call is registered so the service can replay pending actions.
|
|
130
|
+
*/
|
|
131
|
+
fun takePendingActions(callId: String): List<CallAction> {
|
|
132
|
+
val list = pendingActionsByCallId.remove(callId) ?: return emptyList()
|
|
133
|
+
synchronized(list) { return list.toList() }
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
fun clearAll() {
|
|
137
|
+
synchronized(pendingPromises) {
|
|
138
|
+
pendingTimeouts.values.forEach { mainHandler.removeCallbacks(it) }
|
|
139
|
+
pendingTimeouts.clear()
|
|
140
|
+
pendingPromises.clear()
|
|
141
|
+
}
|
|
142
|
+
trackedCallIds.clear()
|
|
143
|
+
pendingActionsByCallId.clear()
|
|
144
|
+
}
|
|
145
|
+
}
|