@stream-io/react-native-callingx 0.1.0-beta.4 → 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 (42) hide show
  1. package/README.md +0 -1
  2. package/android/build.gradle +9 -0
  3. package/android/src/main/java/io/getstream/rn/callingx/CallService.kt +69 -45
  4. package/android/src/main/java/io/getstream/rn/callingx/CallingxEventEmitterAdapter.kt +7 -0
  5. package/android/src/main/java/io/getstream/rn/callingx/{CallingxModule.kt → CallingxModuleImpl.kt} +194 -103
  6. package/android/src/main/java/io/getstream/rn/callingx/notifications/CallNotificationManager.kt +9 -9
  7. package/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationIntentFactory.kt +8 -8
  8. package/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationReceiverActivity.kt +7 -7
  9. package/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationReceiverService.kt +7 -7
  10. package/android/src/main/java/io/getstream/rn/callingx/repo/TelecomCallRepository.kt +3 -0
  11. package/android/src/newarch/java/io/getstream/rn/callingx/CallingxModule.kt +148 -0
  12. package/android/src/oldarch/java/io/getstream/rn/callingx/CallingxModule.kt +177 -0
  13. package/android/src/oldarch/java/io/getstream/rn/callingx/CallingxPackage.kt +16 -0
  14. package/dist/module/CallingxModule.js +2 -2
  15. package/dist/module/CallingxModule.js.map +1 -1
  16. package/dist/module/EventManager.js +11 -4
  17. package/dist/module/EventManager.js.map +1 -1
  18. package/dist/module/spec/NativeCallingx.js +4 -2
  19. package/dist/module/spec/NativeCallingx.js.map +1 -1
  20. package/dist/module/utils/utils.js +3 -0
  21. package/dist/module/utils/utils.js.map +1 -1
  22. package/dist/typescript/src/CallingxModule.d.ts +1 -1
  23. package/dist/typescript/src/CallingxModule.d.ts.map +1 -1
  24. package/dist/typescript/src/EventManager.d.ts.map +1 -1
  25. package/dist/typescript/src/spec/NativeCallingx.d.ts +3 -3
  26. package/dist/typescript/src/spec/NativeCallingx.d.ts.map +1 -1
  27. package/dist/typescript/src/types.d.ts +2 -2
  28. package/dist/typescript/src/types.d.ts.map +1 -1
  29. package/dist/typescript/src/utils/utils.d.ts +1 -0
  30. package/dist/typescript/src/utils/utils.d.ts.map +1 -1
  31. package/ios/Callingx.mm +326 -22
  32. package/ios/CallingxCall.swift +105 -0
  33. package/ios/CallingxImpl.swift +136 -70
  34. package/ios/CallingxPublic.h +2 -5
  35. package/ios/UUIDStorage.swift +71 -26
  36. package/package.json +3 -3
  37. package/src/CallingxModule.ts +2 -2
  38. package/src/EventManager.ts +18 -5
  39. package/src/spec/NativeCallingx.ts +12 -3
  40. package/src/types.ts +2 -2
  41. package/src/utils/utils.ts +3 -0
  42. /package/android/src/{main → newarch}/java/io/getstream/rn/callingx/CallingxPackage.kt +0 -0
package/README.md CHANGED
@@ -68,7 +68,6 @@ withCompletionHandler:(void (^)(void))completion {
68
68
  supportsDTMF:NO
69
69
  supportsGrouping:NO
70
70
  supportsUngrouping:NO
71
- fromPushKit:YES
72
71
  payload:payload.dictionaryPayload
73
72
  withCompletionHandler:completion];
74
73
  }
@@ -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
  }
@@ -1,5 +1,6 @@
1
1
  package io.getstream.rn.callingx
2
2
 
3
+ import android.app.Notification
3
4
  import android.app.Service
4
5
  import android.content.Intent
5
6
  import android.content.pm.ServiceInfo
@@ -57,6 +58,7 @@ class CallService : Service(), CallRepository.Listener {
57
58
  internal const val ACTION_START_BACKGROUND_TASK = "start_background_task"
58
59
  internal const val ACTION_STOP_BACKGROUND_TASK = "stop_background_task"
59
60
  internal const val ACTION_STOP_SERVICE = "stop_service"
61
+ internal const val ACTION_REGISTRATION_FAILED = "registration_failed"
60
62
  }
61
63
 
62
64
  inner class CallServiceBinder : Binder() {
@@ -81,7 +83,7 @@ class CallService : Service(), CallRepository.Listener {
81
83
  callRepository = CallRepositoryFactory.create(applicationContext)
82
84
  callRepository.setListener(this)
83
85
 
84
- sendBroadcastEvent(CallingxModule.SERVICE_READY_ACTION)
86
+ sendBroadcastEvent(CallingxModuleImpl.SERVICE_READY_ACTION)
85
87
  }
86
88
 
87
89
  override fun onDestroy() {
@@ -179,8 +181,7 @@ class CallService : Service(), CallRepository.Listener {
179
181
  )
180
182
  //fallback if for some reason startForeground method is not called in onStartCommand method
181
183
  val notification = notificationManager.createNotification(call)
182
- startForeground(CallNotificationManager.NOTIFICATION_ID, notification)
183
- isInForeground = true
184
+ startForegroundSafely(notification)
184
185
  }
185
186
  }
186
187
  is Call.Unregistered -> {
@@ -207,9 +208,9 @@ class CallService : Service(), CallRepository.Listener {
207
208
  }
208
209
 
209
210
  override fun onIsCallAnswered(callId: String, source: CallRepository.EventSource) {
210
- sendBroadcastEvent(CallingxModule.CALL_ANSWERED_ACTION) {
211
- putExtra(CallingxModule.EXTRA_CALL_ID, callId)
212
- 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())
213
214
  }
214
215
  }
215
216
 
@@ -220,58 +221,53 @@ class CallService : Service(), CallRepository.Listener {
220
221
  ) {
221
222
  // we're not passing the callId here to prevent infinite loops
222
223
  // callEnd event with callId will sent only when after interaction with notification buttons
223
- sendBroadcastEvent(CallingxModule.CALL_END_ACTION) {
224
+ sendBroadcastEvent(CallingxModuleImpl.CALL_END_ACTION) {
224
225
  if (callId != null) {
225
- putExtra(CallingxModule.EXTRA_CALL_ID, callId)
226
+ putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
226
227
  }
227
- putExtra(CallingxModule.EXTRA_DISCONNECT_CAUSE, getDisconnectCauseString(cause))
228
- putExtra(CallingxModule.EXTRA_SOURCE, source.name.lowercase())
228
+ putExtra(CallingxModuleImpl.EXTRA_DISCONNECT_CAUSE, getDisconnectCauseString(cause))
229
+ putExtra(CallingxModuleImpl.EXTRA_SOURCE, source.name.lowercase())
229
230
  }
230
231
  }
231
232
 
232
233
  override fun onIsCallInactive(callId: String) {
233
- sendBroadcastEvent(CallingxModule.CALL_INACTIVE_ACTION) {
234
- putExtra(CallingxModule.EXTRA_CALL_ID, callId)
234
+ sendBroadcastEvent(CallingxModuleImpl.CALL_INACTIVE_ACTION) {
235
+ putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
235
236
  }
236
237
  }
237
238
 
238
239
  override fun onIsCallActive(callId: String) {
239
- sendBroadcastEvent(CallingxModule.CALL_ACTIVE_ACTION) {
240
- putExtra(CallingxModule.EXTRA_CALL_ID, callId)
240
+ sendBroadcastEvent(CallingxModuleImpl.CALL_ACTIVE_ACTION) {
241
+ putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
241
242
  }
242
243
  }
243
244
 
244
245
  override fun onCallRegistered(callId: String, incoming: Boolean) {
245
246
  if (incoming) {
246
- sendBroadcastEvent(CallingxModule.CALL_REGISTERED_INCOMING_ACTION) {
247
- putExtra(CallingxModule.EXTRA_CALL_ID, callId)
247
+ sendBroadcastEvent(CallingxModuleImpl.CALL_REGISTERED_INCOMING_ACTION) {
248
+ putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
248
249
  }
249
250
  } else {
250
- sendBroadcastEvent(CallingxModule.CALL_REGISTERED_ACTION) {
251
- putExtra(CallingxModule.EXTRA_CALL_ID, callId)
251
+ sendBroadcastEvent(CallingxModuleImpl.CALL_REGISTERED_ACTION) {
252
+ putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
252
253
  }
253
254
  }
254
255
  }
255
256
 
256
257
  override fun onMuteCallChanged(callId: String, isMuted: Boolean) {
257
- sendBroadcastEvent(CallingxModule.CALL_MUTED_ACTION) {
258
- putExtra(CallingxModule.EXTRA_CALL_ID, callId)
259
- putExtra(CallingxModule.EXTRA_MUTED, isMuted)
258
+ sendBroadcastEvent(CallingxModuleImpl.CALL_MUTED_ACTION) {
259
+ putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
260
+ putExtra(CallingxModuleImpl.EXTRA_MUTED, isMuted)
260
261
  }
261
262
  }
262
263
 
263
264
  override fun onCallEndpointChanged(callId: String, endpoint: String) {
264
- sendBroadcastEvent(CallingxModule.CALL_ENDPOINT_CHANGED_ACTION) {
265
- putExtra(CallingxModule.EXTRA_CALL_ID, callId)
266
- 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)
267
268
  }
268
269
  }
269
270
 
270
- public fun isCallRegistered(callId: String): Boolean {
271
- val currentCall = callRepository.currentCall.value
272
- return currentCall is Call.Registered && currentCall.id == callId
273
- }
274
-
275
271
  public fun hasRegisteredCall(): Boolean {
276
272
  val currentCall = callRepository.currentCall.value
277
273
  return currentCall is Call.Registered
@@ -303,33 +299,33 @@ class CallService : Service(), CallRepository.Listener {
303
299
 
304
300
  private fun registerCall(intent: Intent, incoming: Boolean) {
305
301
  debugLog(TAG, "[service] registerCall: ${if (incoming) "in" else "out"} call")
302
+ val callInfo = extractIntentParams(intent)
306
303
 
307
- // If we have an ongoing call ignore command
304
+ // If we have an ongoing call, notify the module that registration is
305
+ // already done (so the pending promise resolves) and skip re-registration.
308
306
  if (callRepository.currentCall.value is Call.Registered) {
309
307
  Log.w(TAG, "[service] registerCall: Call already registered, ignoring new call request")
308
+ if (incoming) {
309
+ sendBroadcastEvent(CallingxModuleImpl.CALL_REGISTERED_INCOMING_ACTION) {
310
+ putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callInfo.callId)
311
+ }
312
+ } else {
313
+ sendBroadcastEvent(CallingxModuleImpl.CALL_REGISTERED_ACTION) {
314
+ putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callInfo.callId)
315
+ }
316
+ }
310
317
  return
311
318
  }
312
-
313
- val callInfo = extractIntentParams(intent)
314
319
  val tempCall = callRepository.getTempCall(callInfo, incoming)
315
320
 
316
321
  //it is better to invoke startForeground method synchronously inside onStartCommand method
317
322
  if (!isInForeground) {
318
323
  debugLog(
319
- TAG,
320
- "[service] registerCall: Starting foreground for call: ${callInfo.callId}"
321
- )
324
+ TAG,
325
+ "[service] registerCall: Starting foreground for call: ${callInfo.callId}"
326
+ )
322
327
  val notification = notificationManager.createNotification(tempCall)
323
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
324
- startForeground(
325
- CallNotificationManager.NOTIFICATION_ID,
326
- notification,
327
- ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL
328
- )
329
- } else {
330
- startForeground(CallNotificationManager.NOTIFICATION_ID, notification)
331
- }
332
- isInForeground = true
328
+ startForegroundSafely(notification)
333
329
  }
334
330
 
335
331
  scope.launch {
@@ -345,6 +341,10 @@ class CallService : Service(), CallRepository.Listener {
345
341
  } catch (e: Exception) {
346
342
  Log.e(TAG, "[service] registerCall: Error registering call: ${e.message}")
347
343
 
344
+ sendBroadcastEvent(CallingxModuleImpl.CALL_REGISTRATION_FAILED_ACTION) {
345
+ putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callInfo.callId)
346
+ }
347
+
348
348
  if (isInForeground) {
349
349
  stopForeground(STOP_FOREGROUND_REMOVE)
350
350
  isInForeground = false
@@ -357,6 +357,30 @@ class CallService : Service(), CallRepository.Listener {
357
357
  }
358
358
  }
359
359
 
360
+ private fun startForegroundSafely(notification: Notification) {
361
+ try {
362
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
363
+ startForeground(
364
+ CallNotificationManager.NOTIFICATION_ID,
365
+ notification,
366
+ ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL
367
+ )
368
+ } else {
369
+ startForeground(CallNotificationManager.NOTIFICATION_ID, notification)
370
+ }
371
+ isInForeground = true
372
+ } catch (e: Exception) {
373
+ // If starting the foreground service fails (for example due to background start
374
+ // restrictions or notification issues), we log the error but avoid crashing the
375
+ // process so the rest of the call flow can continue and be recovered by Telecom.
376
+ Log.e(
377
+ TAG,
378
+ "[service] startForegroundSafely: Failed to start foreground service: ${e.message}",
379
+ e
380
+ )
381
+ }
382
+ }
383
+
360
384
  private fun updateCall(intent: Intent) {
361
385
  val callInfo = extractIntentParams(intent)
362
386
  callRepository.updateCall(
@@ -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
+ }