@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.
Files changed (28) hide show
  1. package/android/build.gradle +9 -0
  2. package/android/src/main/java/io/getstream/rn/callingx/CallService.kt +28 -43
  3. package/android/src/main/java/io/getstream/rn/callingx/CallingxEventEmitterAdapter.kt +7 -0
  4. package/android/src/main/java/io/getstream/rn/callingx/{CallingxModule.kt → CallingxModuleImpl.kt} +53 -51
  5. package/android/src/main/java/io/getstream/rn/callingx/notifications/CallNotificationManager.kt +9 -9
  6. package/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationIntentFactory.kt +8 -8
  7. package/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationReceiverActivity.kt +7 -7
  8. package/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationReceiverService.kt +7 -7
  9. package/android/src/newarch/java/io/getstream/rn/callingx/CallingxModule.kt +148 -0
  10. package/android/src/oldarch/java/io/getstream/rn/callingx/CallingxModule.kt +177 -0
  11. package/android/src/oldarch/java/io/getstream/rn/callingx/CallingxPackage.kt +16 -0
  12. package/dist/module/EventManager.js +11 -4
  13. package/dist/module/EventManager.js.map +1 -1
  14. package/dist/module/spec/NativeCallingx.js +4 -2
  15. package/dist/module/spec/NativeCallingx.js.map +1 -1
  16. package/dist/module/utils/utils.js +3 -0
  17. package/dist/module/utils/utils.js.map +1 -1
  18. package/dist/typescript/src/EventManager.d.ts.map +1 -1
  19. package/dist/typescript/src/spec/NativeCallingx.d.ts +2 -2
  20. package/dist/typescript/src/spec/NativeCallingx.d.ts.map +1 -1
  21. package/dist/typescript/src/utils/utils.d.ts +1 -0
  22. package/dist/typescript/src/utils/utils.d.ts.map +1 -1
  23. package/ios/Callingx.mm +312 -18
  24. package/package.json +1 -1
  25. package/src/EventManager.ts +18 -5
  26. package/src/spec/NativeCallingx.ts +11 -2
  27. package/src/utils/utils.ts +3 -0
  28. /package/android/src/{main → newarch}/java/io/getstream/rn/callingx/CallingxPackage.kt +0 -0
@@ -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(CallingxModule.SERVICE_READY_ACTION)
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(CallingxModule.CALL_ANSWERED_ACTION) {
217
- putExtra(CallingxModule.EXTRA_CALL_ID, callId)
218
- putExtra(CallingxModule.EXTRA_SOURCE, source.name.lowercase())
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(CallingxModule.CALL_END_ACTION) {
224
+ sendBroadcastEvent(CallingxModuleImpl.CALL_END_ACTION) {
233
225
  if (callId != null) {
234
- putExtra(CallingxModule.EXTRA_CALL_ID, callId)
226
+ putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
235
227
  }
236
- putExtra(CallingxModule.EXTRA_DISCONNECT_CAUSE, getDisconnectCauseString(cause))
237
- putExtra(CallingxModule.EXTRA_SOURCE, source.name.lowercase())
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(CallingxModule.CALL_INACTIVE_ACTION) {
243
- putExtra(CallingxModule.EXTRA_CALL_ID, callId)
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(CallingxModule.CALL_ACTIVE_ACTION) {
249
- putExtra(CallingxModule.EXTRA_CALL_ID, callId)
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(CallingxModule.CALL_REGISTERED_INCOMING_ACTION) {
256
- putExtra(CallingxModule.EXTRA_CALL_ID, callId)
247
+ sendBroadcastEvent(CallingxModuleImpl.CALL_REGISTERED_INCOMING_ACTION) {
248
+ putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
257
249
  }
258
250
  } else {
259
- sendBroadcastEvent(CallingxModule.CALL_REGISTERED_ACTION) {
260
- putExtra(CallingxModule.EXTRA_CALL_ID, callId)
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(CallingxModule.CALL_MUTED_ACTION) {
267
- putExtra(CallingxModule.EXTRA_CALL_ID, callId)
268
- putExtra(CallingxModule.EXTRA_MUTED, isMuted)
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(CallingxModule.CALL_ENDPOINT_CHANGED_ACTION) {
274
- putExtra(CallingxModule.EXTRA_CALL_ID, callId)
275
- putExtra(CallingxModule.EXTRA_AUDIO_ENDPOINT, endpoint)
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(CallingxModule.CALL_REGISTERED_INCOMING_ACTION) {
324
- putExtra(CallingxModule.EXTRA_CALL_ID, callInfo.callId)
309
+ sendBroadcastEvent(CallingxModuleImpl.CALL_REGISTERED_INCOMING_ACTION) {
310
+ putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callInfo.callId)
325
311
  }
326
312
  } else {
327
- sendBroadcastEvent(CallingxModule.CALL_REGISTERED_ACTION) {
328
- putExtra(CallingxModule.EXTRA_CALL_ID, callInfo.callId)
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(CallingxModule.CALL_REGISTRATION_FAILED_ACTION) {
360
- putExtra(CallingxModule.EXTRA_CALL_ID, callInfo.callId)
344
+ sendBroadcastEvent(CallingxModuleImpl.CALL_REGISTRATION_FAILED_ACTION) {
345
+ putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callInfo.callId)
361
346
  }
362
347
 
363
348
  if (isInForeground) {
@@ -0,0 +1,7 @@
1
+ package io.getstream.rn.callingx
2
+
3
+ import com.facebook.react.bridge.WritableMap
4
+
5
+ interface CallingxEventEmitterAdapter {
6
+ fun emitNewEvent(value: WritableMap)
7
+ }
@@ -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
- @ReactModule(name = CallingxModule.NAME)
33
- class CallingxModule(reactContext: ReactApplicationContext) : NativeCallingxSpec(reactContext) {
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
- reactContext.registerReceiver(
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
- reactContext.registerReceiver(callEventBroadcastReceiver, getReceiverFilter())
111
+ reactApplicationContext.registerReceiver(callEventBroadcastReceiver, getReceiverFilter())
106
112
  }
107
113
  }
108
114
 
109
- override fun getName(): String = NAME
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
- override fun invalidate() {
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
- override fun setupiOS(options: ReadableMap) {
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
- override fun canPostNotifications(): Boolean {
151
+ fun canPostNotifications(): Boolean {
153
152
  return notificationChannelsManager.getNotificationStatus().canPost
154
153
  }
155
154
 
156
- override fun setShouldRejectCallWhenBusy(shouldReject: Boolean) {
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
- override fun setCurrentCallActive(callId: String, promise: Promise) {
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
- override fun displayIncomingCall(
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
- override fun answerIncomingCall(callId: String, promise: Promise) {
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
- override fun startCall(
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
- override fun updateDisplay(
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
- override fun endCallWithReason(callId: String, reason: Double, promise: Promise) {
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
- override fun endCall(callId: String, promise: Promise) {
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
- override fun isCallTracked(callId: String): Boolean {
329
- val isCallTracked = callService?.isCallTracked(callId) ?: false
330
- debugLog(TAG, "[module] isCallTracked: Is call tracked: $isCallTracked")
331
- return isCallTracked
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
- override fun hasRegisteredCall(): Boolean {
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
- override fun setMutedCall(callId: String, isMuted: Boolean, promise: Promise) {
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
- override fun setOnHoldCall(callId: String, isOnHold: Boolean, promise: Promise) {
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
- override fun startBackgroundTask(taskName: String, timeout: Double, promise: Promise) {
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
- override fun stopBackgroundTask(taskName: String, promise: Promise) {
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
- override fun registerBackgroundTaskAvailable() {
381
+ fun registerBackgroundTaskAvailable() {
388
382
  debugLog(TAG, "[module] registerBackgroundTaskAvailable: Headless task registered")
389
383
  isHeadlessTaskRegistered = true
390
384
  }
391
385
 
392
- override fun isServiceStarted(promise: Promise) {
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
- override fun log(message: String, level: String) {
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
- emitOnNewEvent(value)
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
  }
@@ -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.CallingxModule
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
- CallingxModule.CALL_ANSWERED_ACTION,
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
- CallingxModule.CALL_END_ACTION,
193
+ CallingxModuleImpl.CALL_END_ACTION,
194
194
  call.id
195
195
  ) {
196
196
  putExtra(
197
- CallingxModule.EXTRA_DISCONNECT_CAUSE,
197
+ CallingxModuleImpl.EXTRA_DISCONNECT_CAUSE,
198
198
  getDisconnectCauseString(DisconnectCause(DisconnectCause.REJECTED))
199
199
  )
200
200
  putExtra(
201
- CallingxModule.EXTRA_SOURCE,
201
+ CallingxModuleImpl.EXTRA_SOURCE,
202
202
  CallRepository.EventSource.SYS.name.lowercase()
203
203
  )
204
204
  },
205
205
  NotificationIntentFactory.getPendingNotificationIntent(
206
206
  context,
207
- CallingxModule.CALL_ANSWERED_ACTION,
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
- CallingxModule.CALL_END_ACTION,
218
+ CallingxModuleImpl.CALL_END_ACTION,
219
219
  call.id
220
220
  ) {
221
221
  putExtra(
222
- CallingxModule.EXTRA_DISCONNECT_CAUSE,
222
+ CallingxModuleImpl.EXTRA_DISCONNECT_CAUSE,
223
223
  getDisconnectCauseString(DisconnectCause(DisconnectCause.LOCAL))
224
224
  )
225
225
  putExtra(
226
- CallingxModule.EXTRA_SOURCE,
226
+ CallingxModuleImpl.EXTRA_SOURCE,
227
227
  CallRepository.EventSource.SYS.name.lowercase()
228
228
  )
229
229
  },
@@ -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.CallingxModule
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(CallingxModule.EXTRA_CALL_ID, callId)
33
- putExtra(CallingxModule.EXTRA_SOURCE, source)
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(CallingxModule.EXTRA_CALL_ID, callId)
49
- putExtra(CallingxModule.EXTRA_SOURCE, source)
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(CallingxModule.EXTRA_CALL_ID, callId)
72
- source?.let { putExtra(CallingxModule.EXTRA_SOURCE, it) }
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(CallingxModule.EXTRA_CALL_ID, callId)
93
+ putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
94
94
  addExtras(this)
95
95
  }
96
96
 
@@ -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.CallingxModule
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 == CallingxModule.CALL_ANSWERED_ACTION) {
31
- val callId = intent.getStringExtra(CallingxModule.EXTRA_CALL_ID)
32
- val source = intent.getStringExtra(CallingxModule.EXTRA_SOURCE)
33
- Intent(CallingxModule.CALL_ANSWERED_ACTION)
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(CallingxModule.EXTRA_CALL_ID, callId)
37
- putExtra(CallingxModule.EXTRA_SOURCE, source)
36
+ putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
37
+ putExtra(CallingxModuleImpl.EXTRA_SOURCE, source)
38
38
  }
39
39
  .also { sendBroadcast(it) }
40
40
  }