@stream-io/react-native-callingx 0.1.0-beta.5 → 0.1.0-beta.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.
- package/android/build.gradle +9 -0
- package/android/src/main/java/io/getstream/rn/callingx/CallService.kt +28 -43
- package/android/src/main/java/io/getstream/rn/callingx/CallingxEventEmitterAdapter.kt +7 -0
- package/android/src/main/java/io/getstream/rn/callingx/{CallingxModule.kt → CallingxModuleImpl.kt} +53 -51
- package/android/src/main/java/io/getstream/rn/callingx/notifications/CallNotificationManager.kt +9 -9
- package/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationIntentFactory.kt +8 -8
- package/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationReceiverActivity.kt +7 -7
- package/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationReceiverService.kt +7 -7
- package/android/src/newarch/java/io/getstream/rn/callingx/CallingxModule.kt +148 -0
- package/android/src/oldarch/java/io/getstream/rn/callingx/CallingxModule.kt +177 -0
- package/android/src/oldarch/java/io/getstream/rn/callingx/CallingxPackage.kt +16 -0
- package/dist/module/EventManager.js +11 -4
- package/dist/module/EventManager.js.map +1 -1
- package/dist/module/spec/NativeCallingx.js +4 -2
- package/dist/module/spec/NativeCallingx.js.map +1 -1
- package/dist/module/utils/utils.js +3 -0
- package/dist/module/utils/utils.js.map +1 -1
- package/dist/typescript/src/EventManager.d.ts.map +1 -1
- package/dist/typescript/src/spec/NativeCallingx.d.ts +2 -2
- package/dist/typescript/src/spec/NativeCallingx.d.ts.map +1 -1
- package/dist/typescript/src/utils/utils.d.ts +1 -0
- package/dist/typescript/src/utils/utils.d.ts.map +1 -1
- package/ios/Callingx.mm +312 -18
- package/package.json +1 -1
- package/src/EventManager.ts +18 -5
- package/src/spec/NativeCallingx.ts +11 -2
- package/src/utils/utils.ts +3 -0
- /package/android/src/{main → newarch}/java/io/getstream/rn/callingx/CallingxPackage.kt +0 -0
package/android/build.gradle
CHANGED
|
@@ -26,6 +26,10 @@ def getExtOrIntegerDefault(name) {
|
|
|
26
26
|
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["Callingx_" + name]).toInteger()
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
def isNewArchitectureEnabled() {
|
|
30
|
+
return rootProject.hasProperty("newArchEnabled") && rootProject.newArchEnabled == "true"
|
|
31
|
+
}
|
|
32
|
+
|
|
29
33
|
android {
|
|
30
34
|
namespace "io.getstream.rn.callingx"
|
|
31
35
|
|
|
@@ -63,6 +67,11 @@ android {
|
|
|
63
67
|
"build/generated/source/codegen/java",
|
|
64
68
|
"build/generated/source/codegen/jni"
|
|
65
69
|
]
|
|
70
|
+
if (isNewArchitectureEnabled()) {
|
|
71
|
+
java.srcDirs += ["src/newarch"]
|
|
72
|
+
} else {
|
|
73
|
+
java.srcDirs += ["src/oldarch"]
|
|
74
|
+
}
|
|
66
75
|
}
|
|
67
76
|
}
|
|
68
77
|
}
|
|
@@ -20,7 +20,6 @@ import kotlinx.coroutines.CoroutineScope
|
|
|
20
20
|
import kotlinx.coroutines.SupervisorJob
|
|
21
21
|
import kotlinx.coroutines.cancel
|
|
22
22
|
import kotlinx.coroutines.launch
|
|
23
|
-
import java.util.concurrent.ConcurrentHashMap
|
|
24
23
|
|
|
25
24
|
/**
|
|
26
25
|
* This service handles the app call logic (show notification, record mic, display audio, etc..). It
|
|
@@ -72,7 +71,6 @@ class CallService : Service(), CallRepository.Listener {
|
|
|
72
71
|
|
|
73
72
|
private val binder = CallServiceBinder()
|
|
74
73
|
private val scope: CoroutineScope = CoroutineScope(SupervisorJob())
|
|
75
|
-
private val trackedCallIds = ConcurrentHashMap.newKeySet<String>()
|
|
76
74
|
|
|
77
75
|
private var isInForeground = false
|
|
78
76
|
|
|
@@ -85,7 +83,7 @@ class CallService : Service(), CallRepository.Listener {
|
|
|
85
83
|
callRepository = CallRepositoryFactory.create(applicationContext)
|
|
86
84
|
callRepository.setListener(this)
|
|
87
85
|
|
|
88
|
-
sendBroadcastEvent(
|
|
86
|
+
sendBroadcastEvent(CallingxModuleImpl.SERVICE_READY_ACTION)
|
|
89
87
|
}
|
|
90
88
|
|
|
91
89
|
override fun onDestroy() {
|
|
@@ -102,7 +100,6 @@ class CallService : Service(), CallRepository.Listener {
|
|
|
102
100
|
isInForeground = false
|
|
103
101
|
}
|
|
104
102
|
|
|
105
|
-
trackedCallIds.clear()
|
|
106
103
|
scope.cancel()
|
|
107
104
|
}
|
|
108
105
|
|
|
@@ -188,7 +185,6 @@ class CallService : Service(), CallRepository.Listener {
|
|
|
188
185
|
}
|
|
189
186
|
}
|
|
190
187
|
is Call.Unregistered -> {
|
|
191
|
-
trackedCallIds.remove(call.id)
|
|
192
188
|
notificationManager.updateCallNotification(call)
|
|
193
189
|
|
|
194
190
|
if (isInForeground) {
|
|
@@ -200,7 +196,6 @@ class CallService : Service(), CallRepository.Listener {
|
|
|
200
196
|
stopSelf()
|
|
201
197
|
}
|
|
202
198
|
is Call.None -> {
|
|
203
|
-
trackedCallIds.clear()
|
|
204
199
|
notificationManager.updateCallNotification(call)
|
|
205
200
|
|
|
206
201
|
if (isInForeground) {
|
|
@@ -213,9 +208,9 @@ class CallService : Service(), CallRepository.Listener {
|
|
|
213
208
|
}
|
|
214
209
|
|
|
215
210
|
override fun onIsCallAnswered(callId: String, source: CallRepository.EventSource) {
|
|
216
|
-
sendBroadcastEvent(
|
|
217
|
-
putExtra(
|
|
218
|
-
putExtra(
|
|
211
|
+
sendBroadcastEvent(CallingxModuleImpl.CALL_ANSWERED_ACTION) {
|
|
212
|
+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
|
|
213
|
+
putExtra(CallingxModuleImpl.EXTRA_SOURCE, source.name.lowercase())
|
|
219
214
|
}
|
|
220
215
|
}
|
|
221
216
|
|
|
@@ -224,62 +219,55 @@ class CallService : Service(), CallRepository.Listener {
|
|
|
224
219
|
cause: DisconnectCause,
|
|
225
220
|
source: CallRepository.EventSource
|
|
226
221
|
) {
|
|
227
|
-
if (callId != null) {
|
|
228
|
-
trackedCallIds.remove(callId)
|
|
229
|
-
}
|
|
230
222
|
// we're not passing the callId here to prevent infinite loops
|
|
231
223
|
// callEnd event with callId will sent only when after interaction with notification buttons
|
|
232
|
-
sendBroadcastEvent(
|
|
224
|
+
sendBroadcastEvent(CallingxModuleImpl.CALL_END_ACTION) {
|
|
233
225
|
if (callId != null) {
|
|
234
|
-
putExtra(
|
|
226
|
+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
|
|
235
227
|
}
|
|
236
|
-
putExtra(
|
|
237
|
-
putExtra(
|
|
228
|
+
putExtra(CallingxModuleImpl.EXTRA_DISCONNECT_CAUSE, getDisconnectCauseString(cause))
|
|
229
|
+
putExtra(CallingxModuleImpl.EXTRA_SOURCE, source.name.lowercase())
|
|
238
230
|
}
|
|
239
231
|
}
|
|
240
232
|
|
|
241
233
|
override fun onIsCallInactive(callId: String) {
|
|
242
|
-
sendBroadcastEvent(
|
|
243
|
-
putExtra(
|
|
234
|
+
sendBroadcastEvent(CallingxModuleImpl.CALL_INACTIVE_ACTION) {
|
|
235
|
+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
|
|
244
236
|
}
|
|
245
237
|
}
|
|
246
238
|
|
|
247
239
|
override fun onIsCallActive(callId: String) {
|
|
248
|
-
sendBroadcastEvent(
|
|
249
|
-
putExtra(
|
|
240
|
+
sendBroadcastEvent(CallingxModuleImpl.CALL_ACTIVE_ACTION) {
|
|
241
|
+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
|
|
250
242
|
}
|
|
251
243
|
}
|
|
252
244
|
|
|
253
245
|
override fun onCallRegistered(callId: String, incoming: Boolean) {
|
|
254
246
|
if (incoming) {
|
|
255
|
-
sendBroadcastEvent(
|
|
256
|
-
putExtra(
|
|
247
|
+
sendBroadcastEvent(CallingxModuleImpl.CALL_REGISTERED_INCOMING_ACTION) {
|
|
248
|
+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
|
|
257
249
|
}
|
|
258
250
|
} else {
|
|
259
|
-
sendBroadcastEvent(
|
|
260
|
-
putExtra(
|
|
251
|
+
sendBroadcastEvent(CallingxModuleImpl.CALL_REGISTERED_ACTION) {
|
|
252
|
+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
|
|
261
253
|
}
|
|
262
254
|
}
|
|
263
255
|
}
|
|
264
256
|
|
|
265
257
|
override fun onMuteCallChanged(callId: String, isMuted: Boolean) {
|
|
266
|
-
sendBroadcastEvent(
|
|
267
|
-
putExtra(
|
|
268
|
-
putExtra(
|
|
258
|
+
sendBroadcastEvent(CallingxModuleImpl.CALL_MUTED_ACTION) {
|
|
259
|
+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
|
|
260
|
+
putExtra(CallingxModuleImpl.EXTRA_MUTED, isMuted)
|
|
269
261
|
}
|
|
270
262
|
}
|
|
271
263
|
|
|
272
264
|
override fun onCallEndpointChanged(callId: String, endpoint: String) {
|
|
273
|
-
sendBroadcastEvent(
|
|
274
|
-
putExtra(
|
|
275
|
-
putExtra(
|
|
265
|
+
sendBroadcastEvent(CallingxModuleImpl.CALL_ENDPOINT_CHANGED_ACTION) {
|
|
266
|
+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
|
|
267
|
+
putExtra(CallingxModuleImpl.EXTRA_AUDIO_ENDPOINT, endpoint)
|
|
276
268
|
}
|
|
277
269
|
}
|
|
278
270
|
|
|
279
|
-
public fun isCallTracked(callId: String): Boolean {
|
|
280
|
-
return trackedCallIds.contains(callId)
|
|
281
|
-
}
|
|
282
|
-
|
|
283
271
|
public fun hasRegisteredCall(): Boolean {
|
|
284
272
|
val currentCall = callRepository.currentCall.value
|
|
285
273
|
return currentCall is Call.Registered
|
|
@@ -312,20 +300,18 @@ class CallService : Service(), CallRepository.Listener {
|
|
|
312
300
|
private fun registerCall(intent: Intent, incoming: Boolean) {
|
|
313
301
|
debugLog(TAG, "[service] registerCall: ${if (incoming) "in" else "out"} call")
|
|
314
302
|
val callInfo = extractIntentParams(intent)
|
|
315
|
-
// Track immediately when registration flow starts, mirroring iOS semantics.
|
|
316
|
-
trackedCallIds.add(callInfo.callId)
|
|
317
303
|
|
|
318
304
|
// If we have an ongoing call, notify the module that registration is
|
|
319
305
|
// already done (so the pending promise resolves) and skip re-registration.
|
|
320
306
|
if (callRepository.currentCall.value is Call.Registered) {
|
|
321
307
|
Log.w(TAG, "[service] registerCall: Call already registered, ignoring new call request")
|
|
322
308
|
if (incoming) {
|
|
323
|
-
sendBroadcastEvent(
|
|
324
|
-
putExtra(
|
|
309
|
+
sendBroadcastEvent(CallingxModuleImpl.CALL_REGISTERED_INCOMING_ACTION) {
|
|
310
|
+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callInfo.callId)
|
|
325
311
|
}
|
|
326
312
|
} else {
|
|
327
|
-
sendBroadcastEvent(
|
|
328
|
-
putExtra(
|
|
313
|
+
sendBroadcastEvent(CallingxModuleImpl.CALL_REGISTERED_ACTION) {
|
|
314
|
+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callInfo.callId)
|
|
329
315
|
}
|
|
330
316
|
}
|
|
331
317
|
return
|
|
@@ -354,10 +340,9 @@ class CallService : Service(), CallRepository.Listener {
|
|
|
354
340
|
)
|
|
355
341
|
} catch (e: Exception) {
|
|
356
342
|
Log.e(TAG, "[service] registerCall: Error registering call: ${e.message}")
|
|
357
|
-
trackedCallIds.remove(callInfo.callId)
|
|
358
343
|
|
|
359
|
-
sendBroadcastEvent(
|
|
360
|
-
putExtra(
|
|
344
|
+
sendBroadcastEvent(CallingxModuleImpl.CALL_REGISTRATION_FAILED_ACTION) {
|
|
345
|
+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callInfo.callId)
|
|
361
346
|
}
|
|
362
347
|
|
|
363
348
|
if (isInForeground) {
|
package/android/src/main/java/io/getstream/rn/callingx/{CallingxModule.kt → CallingxModuleImpl.kt}
RENAMED
|
@@ -23,14 +23,16 @@ import com.facebook.react.bridge.ReadableMap
|
|
|
23
23
|
import com.facebook.react.bridge.WritableArray
|
|
24
24
|
import com.facebook.react.bridge.WritableMap
|
|
25
25
|
import com.facebook.react.bridge.WritableNativeArray
|
|
26
|
-
import com.facebook.react.module.annotations.ReactModule
|
|
27
26
|
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
28
27
|
import io.getstream.rn.callingx.model.CallAction
|
|
29
28
|
import io.getstream.rn.callingx.notifications.NotificationChannelsManager
|
|
30
29
|
import io.getstream.rn.callingx.notifications.NotificationsConfig
|
|
30
|
+
import java.util.concurrent.ConcurrentHashMap
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
class CallingxModuleImpl(
|
|
33
|
+
private val reactApplicationContext: ReactApplicationContext,
|
|
34
|
+
private val eventEmitter: CallingxEventEmitterAdapter
|
|
35
|
+
) {
|
|
34
36
|
|
|
35
37
|
companion object {
|
|
36
38
|
const val TAG = "[Callingx] CallingxModule"
|
|
@@ -72,6 +74,10 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
72
74
|
private var canSendEvents = false
|
|
73
75
|
private var isHeadlessTaskRegistered = false
|
|
74
76
|
|
|
77
|
+
// Synchronous call tracking set, updated before async service start to mirror iOS semantics.
|
|
78
|
+
// This ensures isCallTracked() returns true immediately after displayIncomingCall/startCall.
|
|
79
|
+
private val trackedCallIds = ConcurrentHashMap.newKeySet<String>()
|
|
80
|
+
|
|
75
81
|
// Per-callId pending promises for displayIncomingCall awaiting CALL_REGISTERED_INCOMING_ACTION
|
|
76
82
|
private val pendingDisplayPromises = mutableMapOf<String, Promise>()
|
|
77
83
|
private val pendingTimeouts = mutableMapOf<String, Runnable>()
|
|
@@ -95,21 +101,18 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
95
101
|
|
|
96
102
|
init {
|
|
97
103
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
98
|
-
|
|
104
|
+
reactApplicationContext.registerReceiver(
|
|
99
105
|
callEventBroadcastReceiver,
|
|
100
106
|
getReceiverFilter(),
|
|
101
107
|
Context.RECEIVER_NOT_EXPORTED
|
|
102
108
|
)
|
|
103
109
|
} else {
|
|
104
110
|
@Suppress("UnspecifiedRegisterReceiverFlag")
|
|
105
|
-
|
|
111
|
+
reactApplicationContext.registerReceiver(callEventBroadcastReceiver, getReceiverFilter())
|
|
106
112
|
}
|
|
107
113
|
}
|
|
108
114
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
override fun initialize() {
|
|
112
|
-
super.initialize()
|
|
115
|
+
fun initialize() {
|
|
113
116
|
reactApplicationContext.addLifecycleEventListener(appStateListener)
|
|
114
117
|
|
|
115
118
|
tryToBindIfNeeded()
|
|
@@ -117,8 +120,7 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
117
120
|
debugLog(TAG, "[module] initialize: Initializing module")
|
|
118
121
|
}
|
|
119
122
|
|
|
120
|
-
|
|
121
|
-
super.invalidate()
|
|
123
|
+
fun invalidate() {
|
|
122
124
|
debugLog(TAG, "[module] invalidate: Invalidating module")
|
|
123
125
|
|
|
124
126
|
// Clean up pending display promises to prevent leaks
|
|
@@ -128,6 +130,7 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
128
130
|
pendingDisplayPromises.clear()
|
|
129
131
|
}
|
|
130
132
|
|
|
133
|
+
trackedCallIds.clear()
|
|
131
134
|
unbindServiceSafely()
|
|
132
135
|
|
|
133
136
|
reactApplicationContext.removeLifecycleEventListener(appStateListener)
|
|
@@ -135,11 +138,7 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
135
138
|
isModuleInitialized = false
|
|
136
139
|
}
|
|
137
140
|
|
|
138
|
-
|
|
139
|
-
// leave empty
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
override fun setupAndroid(options: ReadableMap) {
|
|
141
|
+
fun setupAndroid(options: ReadableMap) {
|
|
143
142
|
debugLog(TAG, "[module] setupAndroid: Setting up Android: $options")
|
|
144
143
|
val notificationsConfig =
|
|
145
144
|
NotificationsConfig.saveNotificationsConfig(reactApplicationContext, options)
|
|
@@ -149,24 +148,11 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
149
148
|
isModuleInitialized = true
|
|
150
149
|
}
|
|
151
150
|
|
|
152
|
-
|
|
151
|
+
fun canPostNotifications(): Boolean {
|
|
153
152
|
return notificationChannelsManager.getNotificationStatus().canPost
|
|
154
153
|
}
|
|
155
154
|
|
|
156
|
-
|
|
157
|
-
// leave empty
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
override fun getInitialVoipEvents(): WritableArray {
|
|
161
|
-
// leave empty
|
|
162
|
-
return Arguments.createArray()
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
override fun registerVoipToken() {
|
|
166
|
-
// leave empty
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
override fun getInitialEvents(): WritableArray {
|
|
155
|
+
fun getInitialEvents(): WritableArray {
|
|
170
156
|
// NOTE: writabel native array can be consumed only once, think of getting rid from clear
|
|
171
157
|
// event and clear eat immidiate after getting initial events
|
|
172
158
|
val events = delayedEvents
|
|
@@ -176,12 +162,12 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
176
162
|
return events
|
|
177
163
|
}
|
|
178
164
|
|
|
179
|
-
|
|
165
|
+
fun setCurrentCallActive(callId: String, promise: Promise) {
|
|
180
166
|
debugLog(TAG, "[module] activateCall: Activating call: $callId")
|
|
181
167
|
executeServiceAction(callId, CallAction.Activate, promise)
|
|
182
168
|
}
|
|
183
169
|
|
|
184
|
-
|
|
170
|
+
fun displayIncomingCall(
|
|
185
171
|
callId: String,
|
|
186
172
|
phoneNumber: String,
|
|
187
173
|
callerName: String,
|
|
@@ -198,6 +184,8 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
198
184
|
return
|
|
199
185
|
}
|
|
200
186
|
|
|
187
|
+
trackedCallIds.add(callId)
|
|
188
|
+
|
|
201
189
|
// Store the promise keyed by callId; it will be resolved when CALL_REGISTERED_INCOMING_ACTION
|
|
202
190
|
// broadcast is received, or rejected on timeout / registration failure.
|
|
203
191
|
synchronized(pendingDisplayPromises) {
|
|
@@ -232,6 +220,7 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
232
220
|
)
|
|
233
221
|
} catch (e: Exception) {
|
|
234
222
|
Log.e(TAG, "[module] displayIncomingCall: Failed to start foreground service: ${e.message}", e)
|
|
223
|
+
trackedCallIds.remove(callId)
|
|
235
224
|
synchronized(pendingDisplayPromises) {
|
|
236
225
|
pendingTimeouts.remove(callId)?.let { mainHandler.removeCallbacks(it) }
|
|
237
226
|
pendingDisplayPromises.remove(callId)
|
|
@@ -240,7 +229,7 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
240
229
|
}
|
|
241
230
|
}
|
|
242
231
|
|
|
243
|
-
|
|
232
|
+
fun answerIncomingCall(callId: String, promise: Promise) {
|
|
244
233
|
debugLog(TAG, "[module] answerIncomingCall: Answering call: $callId")
|
|
245
234
|
// TODO: get the call type from the call attributes
|
|
246
235
|
val isAudioCall = true // TODO: get the call type from the call attributes
|
|
@@ -250,7 +239,7 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
250
239
|
executeServiceAction(callId, CallAction.Answer(isAudioCall), promise)
|
|
251
240
|
}
|
|
252
241
|
|
|
253
|
-
|
|
242
|
+
fun startCall(
|
|
254
243
|
callId: String,
|
|
255
244
|
phoneNumber: String,
|
|
256
245
|
callerName: String,
|
|
@@ -267,6 +256,8 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
267
256
|
return
|
|
268
257
|
}
|
|
269
258
|
|
|
259
|
+
trackedCallIds.add(callId)
|
|
260
|
+
|
|
270
261
|
try {
|
|
271
262
|
startCallService(
|
|
272
263
|
CallService.ACTION_OUTGOING_CALL,
|
|
@@ -279,11 +270,12 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
279
270
|
promise.resolve(true)
|
|
280
271
|
} catch (e: Exception) {
|
|
281
272
|
Log.e(TAG, "[module] startCall: Failed to start foreground service: ${e.message}", e)
|
|
273
|
+
trackedCallIds.remove(callId)
|
|
282
274
|
promise.reject("START_FOREGROUND_SERVICE_ERROR", e.message, e)
|
|
283
275
|
}
|
|
284
276
|
}
|
|
285
277
|
|
|
286
|
-
|
|
278
|
+
fun updateDisplay(
|
|
287
279
|
callId: String,
|
|
288
280
|
phoneNumber: String,
|
|
289
281
|
callerName: String,
|
|
@@ -313,43 +305,45 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
313
305
|
}
|
|
314
306
|
}
|
|
315
307
|
|
|
316
|
-
|
|
308
|
+
fun endCallWithReason(callId: String, reason: Double, promise: Promise) {
|
|
317
309
|
debugLog(TAG, "[module] endCallWithReason: Ending call: $callId, $reason")
|
|
310
|
+
trackedCallIds.remove(callId)
|
|
318
311
|
val action = CallAction.Disconnect(DisconnectCause(reason.toInt()))
|
|
319
312
|
executeServiceAction(callId, action, promise)
|
|
320
313
|
}
|
|
321
314
|
|
|
322
|
-
|
|
315
|
+
fun endCall(callId: String, promise: Promise) {
|
|
323
316
|
debugLog(TAG, "[module] endCall: Ending call: $callId")
|
|
317
|
+
trackedCallIds.remove(callId)
|
|
324
318
|
val action = CallAction.Disconnect(DisconnectCause(DisconnectCause.LOCAL))
|
|
325
319
|
executeServiceAction(callId, action, promise)
|
|
326
320
|
}
|
|
327
321
|
|
|
328
|
-
|
|
329
|
-
val
|
|
330
|
-
debugLog(TAG, "[module] isCallTracked: Is call tracked: $
|
|
331
|
-
return
|
|
322
|
+
fun isCallTracked(callId: String): Boolean {
|
|
323
|
+
val isTracked = trackedCallIds.contains(callId)
|
|
324
|
+
debugLog(TAG, "[module] isCallTracked: Is call tracked: $isTracked")
|
|
325
|
+
return isTracked
|
|
332
326
|
}
|
|
333
327
|
|
|
334
|
-
|
|
328
|
+
fun hasRegisteredCall(): Boolean {
|
|
335
329
|
val hasRegisteredCall = callService?.hasRegisteredCall() ?: false
|
|
336
330
|
debugLog(TAG, "[module] hasRegisteredCall: Has registered call: $hasRegisteredCall")
|
|
337
331
|
return hasRegisteredCall
|
|
338
332
|
}
|
|
339
333
|
|
|
340
|
-
|
|
334
|
+
fun setMutedCall(callId: String, isMuted: Boolean, promise: Promise) {
|
|
341
335
|
debugLog(TAG, "[module] setMutedCall: Setting muted call: $callId, $isMuted")
|
|
342
336
|
val action = CallAction.ToggleMute(isMuted)
|
|
343
337
|
executeServiceAction(callId, action, promise)
|
|
344
338
|
}
|
|
345
339
|
|
|
346
|
-
|
|
340
|
+
fun setOnHoldCall(callId: String, isOnHold: Boolean, promise: Promise) {
|
|
347
341
|
debugLog(TAG, "[module] setOnHoldCall: Setting on hold call: $callId, $isOnHold")
|
|
348
342
|
val action = if (isOnHold) CallAction.Hold else CallAction.Activate
|
|
349
343
|
executeServiceAction(callId, action, promise)
|
|
350
344
|
}
|
|
351
345
|
|
|
352
|
-
|
|
346
|
+
fun startBackgroundTask(taskName: String, timeout: Double, promise: Promise) {
|
|
353
347
|
try {
|
|
354
348
|
Intent(reactApplicationContext, CallService::class.java)
|
|
355
349
|
.apply {
|
|
@@ -367,7 +361,7 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
367
361
|
}
|
|
368
362
|
}
|
|
369
363
|
|
|
370
|
-
|
|
364
|
+
fun stopBackgroundTask(taskName: String, promise: Promise) {
|
|
371
365
|
try {
|
|
372
366
|
Intent(reactApplicationContext, CallService::class.java)
|
|
373
367
|
.apply {
|
|
@@ -384,12 +378,12 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
384
378
|
}
|
|
385
379
|
}
|
|
386
380
|
|
|
387
|
-
|
|
381
|
+
fun registerBackgroundTaskAvailable() {
|
|
388
382
|
debugLog(TAG, "[module] registerBackgroundTaskAvailable: Headless task registered")
|
|
389
383
|
isHeadlessTaskRegistered = true
|
|
390
384
|
}
|
|
391
385
|
|
|
392
|
-
|
|
386
|
+
fun isServiceStarted(promise: Promise) {
|
|
393
387
|
val isStarted =
|
|
394
388
|
bindingState == BindingState.BOUND ||
|
|
395
389
|
bindingState == BindingState.BINDING ||
|
|
@@ -398,7 +392,7 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
398
392
|
promise.resolve(isStarted)
|
|
399
393
|
}
|
|
400
394
|
|
|
401
|
-
|
|
395
|
+
fun log(message: String, level: String) {
|
|
402
396
|
when (level) {
|
|
403
397
|
"debug" -> debugLog(TAG, "[module] log: $message")
|
|
404
398
|
"info" -> Log.i(TAG, "[module] log: $message")
|
|
@@ -501,7 +495,7 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
501
495
|
putString("eventName", eventName)
|
|
502
496
|
putMap("params", paramsMap)
|
|
503
497
|
}
|
|
504
|
-
|
|
498
|
+
eventEmitter.emitNewEvent(value)
|
|
505
499
|
} else {
|
|
506
500
|
debugLog(TAG, "[module] sendJSEvent: Queueing event: $eventName, $params")
|
|
507
501
|
Arguments.createMap()
|
|
@@ -643,6 +637,9 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
643
637
|
sendJSEvent("didDisplayIncomingCall", params)
|
|
644
638
|
}
|
|
645
639
|
CALL_REGISTRATION_FAILED_ACTION -> {
|
|
640
|
+
if (callId != null) {
|
|
641
|
+
trackedCallIds.remove(callId)
|
|
642
|
+
}
|
|
646
643
|
// Reject the pending displayIncomingCall promise for this callId
|
|
647
644
|
if (callId != null) {
|
|
648
645
|
synchronized(pendingDisplayPromises) {
|
|
@@ -666,6 +663,11 @@ class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec
|
|
|
666
663
|
params.putString("source", source)
|
|
667
664
|
}
|
|
668
665
|
if (source == "app") {
|
|
666
|
+
if (callId != null) {
|
|
667
|
+
//we stop tracking the call only when it was handled by the app
|
|
668
|
+
//in case source is "sys" we still need to know that call is tracked, otherwise we'll unable to end call from js side
|
|
669
|
+
trackedCallIds.remove(callId)
|
|
670
|
+
}
|
|
669
671
|
// means the call was disconnected, we're ready to unbind the service
|
|
670
672
|
unbindServiceSafely()
|
|
671
673
|
}
|
package/android/src/main/java/io/getstream/rn/callingx/notifications/CallNotificationManager.kt
CHANGED
|
@@ -13,7 +13,7 @@ import androidx.core.app.NotificationManagerCompat
|
|
|
13
13
|
import androidx.core.app.Person
|
|
14
14
|
import androidx.core.graphics.drawable.IconCompat
|
|
15
15
|
import io.getstream.rn.callingx.CallService
|
|
16
|
-
import io.getstream.rn.callingx.
|
|
16
|
+
import io.getstream.rn.callingx.CallingxModuleImpl
|
|
17
17
|
import io.getstream.rn.callingx.R
|
|
18
18
|
import io.getstream.rn.callingx.ResourceUtils
|
|
19
19
|
import io.getstream.rn.callingx.debugLog
|
|
@@ -78,7 +78,7 @@ class CallNotificationManager(
|
|
|
78
78
|
val contentIntent =
|
|
79
79
|
NotificationIntentFactory.getLaunchActivityIntent(
|
|
80
80
|
context,
|
|
81
|
-
|
|
81
|
+
CallingxModuleImpl.CALL_ANSWERED_ACTION,
|
|
82
82
|
call.id
|
|
83
83
|
)
|
|
84
84
|
val callStyle = createCallStyle(call)
|
|
@@ -190,21 +190,21 @@ class CallNotificationManager(
|
|
|
190
190
|
caller,
|
|
191
191
|
NotificationIntentFactory.getPendingBroadcastIntent(
|
|
192
192
|
context,
|
|
193
|
-
|
|
193
|
+
CallingxModuleImpl.CALL_END_ACTION,
|
|
194
194
|
call.id
|
|
195
195
|
) {
|
|
196
196
|
putExtra(
|
|
197
|
-
|
|
197
|
+
CallingxModuleImpl.EXTRA_DISCONNECT_CAUSE,
|
|
198
198
|
getDisconnectCauseString(DisconnectCause(DisconnectCause.REJECTED))
|
|
199
199
|
)
|
|
200
200
|
putExtra(
|
|
201
|
-
|
|
201
|
+
CallingxModuleImpl.EXTRA_SOURCE,
|
|
202
202
|
CallRepository.EventSource.SYS.name.lowercase()
|
|
203
203
|
)
|
|
204
204
|
},
|
|
205
205
|
NotificationIntentFactory.getPendingNotificationIntent(
|
|
206
206
|
context,
|
|
207
|
-
|
|
207
|
+
CallingxModuleImpl.CALL_ANSWERED_ACTION,
|
|
208
208
|
call.id,
|
|
209
209
|
CallRepository.EventSource.SYS.name.lowercase()
|
|
210
210
|
)
|
|
@@ -215,15 +215,15 @@ class CallNotificationManager(
|
|
|
215
215
|
caller,
|
|
216
216
|
NotificationIntentFactory.getPendingBroadcastIntent(
|
|
217
217
|
context,
|
|
218
|
-
|
|
218
|
+
CallingxModuleImpl.CALL_END_ACTION,
|
|
219
219
|
call.id
|
|
220
220
|
) {
|
|
221
221
|
putExtra(
|
|
222
|
-
|
|
222
|
+
CallingxModuleImpl.EXTRA_DISCONNECT_CAUSE,
|
|
223
223
|
getDisconnectCauseString(DisconnectCause(DisconnectCause.LOCAL))
|
|
224
224
|
)
|
|
225
225
|
putExtra(
|
|
226
|
-
|
|
226
|
+
CallingxModuleImpl.EXTRA_SOURCE,
|
|
227
227
|
CallRepository.EventSource.SYS.name.lowercase()
|
|
228
228
|
)
|
|
229
229
|
},
|
package/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationIntentFactory.kt
CHANGED
|
@@ -4,7 +4,7 @@ import android.app.PendingIntent
|
|
|
4
4
|
import android.content.Context
|
|
5
5
|
import android.content.Intent
|
|
6
6
|
import android.os.Build
|
|
7
|
-
import io.getstream.rn.callingx.
|
|
7
|
+
import io.getstream.rn.callingx.CallingxModuleImpl
|
|
8
8
|
|
|
9
9
|
object NotificationIntentFactory {
|
|
10
10
|
// Stable request codes for PendingIntents
|
|
@@ -29,8 +29,8 @@ object NotificationIntentFactory {
|
|
|
29
29
|
val intent =
|
|
30
30
|
Intent(context, NotificationReceiverService::class.java).apply {
|
|
31
31
|
this.action = action
|
|
32
|
-
putExtra(
|
|
33
|
-
putExtra(
|
|
32
|
+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
|
|
33
|
+
putExtra(CallingxModuleImpl.EXTRA_SOURCE, source)
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
return PendingIntent.getService(
|
|
@@ -45,8 +45,8 @@ object NotificationIntentFactory {
|
|
|
45
45
|
val receiverIntent =
|
|
46
46
|
Intent(context, NotificationReceiverActivity::class.java).apply {
|
|
47
47
|
this.action = action
|
|
48
|
-
putExtra(
|
|
49
|
-
putExtra(
|
|
48
|
+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
|
|
49
|
+
putExtra(CallingxModuleImpl.EXTRA_SOURCE, source)
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
val launchActivity = context.packageManager.getLaunchIntentForPackage(context.packageName)
|
|
@@ -68,8 +68,8 @@ object NotificationIntentFactory {
|
|
|
68
68
|
val callIntent =
|
|
69
69
|
Intent(launchIntent).apply {
|
|
70
70
|
this.action = action
|
|
71
|
-
putExtra(
|
|
72
|
-
source?.let { putExtra(
|
|
71
|
+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
|
|
72
|
+
source?.let { putExtra(CallingxModuleImpl.EXTRA_SOURCE, it) }
|
|
73
73
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
|
74
74
|
}
|
|
75
75
|
|
|
@@ -90,7 +90,7 @@ object NotificationIntentFactory {
|
|
|
90
90
|
val intent =
|
|
91
91
|
Intent(action).apply {
|
|
92
92
|
setPackage(context.packageName)
|
|
93
|
-
putExtra(
|
|
93
|
+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
|
|
94
94
|
addExtras(this)
|
|
95
95
|
}
|
|
96
96
|
|
package/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationReceiverActivity.kt
CHANGED
|
@@ -3,7 +3,7 @@ package io.getstream.rn.callingx.notifications
|
|
|
3
3
|
import android.app.Activity
|
|
4
4
|
import android.content.Intent
|
|
5
5
|
import android.os.Bundle
|
|
6
|
-
import io.getstream.rn.callingx.
|
|
6
|
+
import io.getstream.rn.callingx.CallingxModuleImpl
|
|
7
7
|
|
|
8
8
|
// For Android 12+
|
|
9
9
|
class NotificationReceiverActivity : Activity() {
|
|
@@ -27,14 +27,14 @@ class NotificationReceiverActivity : Activity() {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
//we need it only for answered call event, as for cold start case we need to send broadcast event and to launch the app
|
|
30
|
-
if (intent.action ==
|
|
31
|
-
val callId = intent.getStringExtra(
|
|
32
|
-
val source = intent.getStringExtra(
|
|
33
|
-
Intent(
|
|
30
|
+
if (intent.action == CallingxModuleImpl.CALL_ANSWERED_ACTION) {
|
|
31
|
+
val callId = intent.getStringExtra(CallingxModuleImpl.EXTRA_CALL_ID)
|
|
32
|
+
val source = intent.getStringExtra(CallingxModuleImpl.EXTRA_SOURCE)
|
|
33
|
+
Intent(CallingxModuleImpl.CALL_ANSWERED_ACTION)
|
|
34
34
|
.apply {
|
|
35
35
|
setPackage(packageName)
|
|
36
|
-
putExtra(
|
|
37
|
-
putExtra(
|
|
36
|
+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
|
|
37
|
+
putExtra(CallingxModuleImpl.EXTRA_SOURCE, source)
|
|
38
38
|
}
|
|
39
39
|
.also { sendBroadcast(it) }
|
|
40
40
|
}
|