@qusaieilouti99/call-manager 0.1.23 → 0.1.25
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/src/main/java/com/qusaieilouti99/callmanager/CallActivity.kt +1 -0
- package/android/src/main/java/com/qusaieilouti99/callmanager/CallEngine.kt +141 -91
- package/android/src/main/java/com/qusaieilouti99/callmanager/CallEventType.kt +15 -0
- package/android/src/main/java/com/qusaieilouti99/callmanager/CallForegroundService.kt +1 -0
- package/android/src/main/java/com/qusaieilouti99/callmanager/CallManagerModule.kt +9 -8
- package/android/src/main/java/com/qusaieilouti99/callmanager/CallNotificationActionReceiver.kt +1 -0
- package/android/src/main/java/com/qusaieilouti99/callmanager/MyConnection.kt +30 -28
- package/android/src/main/java/com/qusaieilouti99/callmanager/MyConnectionService.kt +1 -0
- package/lib/module/NativeCallManager.js +1 -2
- package/lib/module/NativeCallManager.js.map +1 -1
- package/lib/module/index.js +11 -2
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NativeCallManager.d.ts +0 -2
- package/lib/typescript/src/NativeCallManager.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +9 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/NativeCallManager.ts +0 -3
- package/src/index.tsx +14 -2
|
@@ -15,8 +15,9 @@ import android.app.Person
|
|
|
15
15
|
import java.util.concurrent.ConcurrentHashMap
|
|
16
16
|
import android.media.AudioDeviceInfo
|
|
17
17
|
import android.media.AudioManager
|
|
18
|
-
import android.
|
|
19
|
-
import
|
|
18
|
+
import android.os.PowerManager
|
|
19
|
+
import org.json.JSONArray
|
|
20
|
+
import org.json.JSONObject
|
|
20
21
|
|
|
21
22
|
object CallEngine {
|
|
22
23
|
private const val TAG = "CallEngine"
|
|
@@ -28,6 +29,7 @@ object CallEngine {
|
|
|
28
29
|
|
|
29
30
|
private var ringtone: android.media.Ringtone? = null
|
|
30
31
|
private var audioManager: AudioManager? = null
|
|
32
|
+
private var wakeLock: PowerManager.WakeLock? = null
|
|
31
33
|
|
|
32
34
|
// --- Multi-call state ---
|
|
33
35
|
private val activeCalls = ConcurrentHashMap<String, CallInfo>() // callId -> CallInfo
|
|
@@ -44,28 +46,48 @@ object CallEngine {
|
|
|
44
46
|
INCOMING, ACTIVE, HELD, ENDED
|
|
45
47
|
}
|
|
46
48
|
|
|
49
|
+
// --- Event handler for JS ---
|
|
50
|
+
private var eventHandler: ((CallEventType, String) -> Unit)? = null
|
|
51
|
+
|
|
52
|
+
fun setEventHandler(handler: ((CallEventType, String) -> Unit)?) {
|
|
53
|
+
eventHandler = handler
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
fun emitEvent(type: CallEventType, data: JSONObject) {
|
|
57
|
+
eventHandler?.invoke(type, data.toString())
|
|
58
|
+
}
|
|
59
|
+
|
|
47
60
|
// --- Public API ---
|
|
48
61
|
|
|
49
62
|
fun setCanMakeMultipleCalls(allow: Boolean) {
|
|
50
63
|
canMakeMultipleCalls = allow
|
|
51
64
|
}
|
|
52
65
|
|
|
66
|
+
fun getCurrentCallState(): String {
|
|
67
|
+
val calls = getActiveCalls()
|
|
68
|
+
if (calls.isEmpty()) return ""
|
|
69
|
+
val jsonArray = JSONArray()
|
|
70
|
+
calls.forEach {
|
|
71
|
+
val obj = JSONObject()
|
|
72
|
+
obj.put("callId", it.callId)
|
|
73
|
+
obj.put("callData", it.callData)
|
|
74
|
+
obj.put("state", it.state.name)
|
|
75
|
+
jsonArray.put(obj)
|
|
76
|
+
}
|
|
77
|
+
return jsonArray.toString()
|
|
78
|
+
}
|
|
79
|
+
|
|
53
80
|
fun reportIncomingCall(context: Context, callId: String, callData: String) {
|
|
54
81
|
Log.d(TAG, "reportIncomingCall: $callId, $callData")
|
|
55
82
|
val callerName = try {
|
|
56
|
-
val json =
|
|
83
|
+
val json = JSONObject(callData)
|
|
57
84
|
json.optString("name", "Unknown")
|
|
58
85
|
} catch (e: Exception) { "Unknown" }
|
|
59
86
|
|
|
60
|
-
// If not allowed, auto-hold or reject current call
|
|
61
87
|
if (!canMakeMultipleCalls && activeCalls.isNotEmpty()) {
|
|
62
|
-
// Option 1: Auto-hold current call
|
|
63
88
|
activeCalls.values.forEach { it.state = CallState.HELD }
|
|
64
|
-
// Option 2: Reject new call (uncomment to use)
|
|
65
|
-
// return
|
|
66
89
|
}
|
|
67
90
|
|
|
68
|
-
// Add to active calls
|
|
69
91
|
activeCalls[callId] = CallInfo(callId, callData, CallState.INCOMING)
|
|
70
92
|
currentCallId = callId
|
|
71
93
|
|
|
@@ -87,19 +109,35 @@ object CallEngine {
|
|
|
87
109
|
Log.d(TAG, "answerCall: $callId")
|
|
88
110
|
activeCalls[callId]?.state = CallState.ACTIVE
|
|
89
111
|
currentCallId = callId
|
|
90
|
-
// Optionally, auto-hold other calls
|
|
91
112
|
if (!canMakeMultipleCalls) {
|
|
92
113
|
activeCalls.filter { it.key != callId }.values.forEach { it.state = CallState.HELD }
|
|
93
114
|
}
|
|
115
|
+
emitEvent(CallEventType.CALL_ANSWERED, JSONObject().put("callId", callId))
|
|
94
116
|
notifyCallStateChanged(context)
|
|
95
117
|
}
|
|
96
118
|
|
|
97
119
|
fun holdCall(context: Context, callId: String) {
|
|
98
120
|
Log.d(TAG, "holdCall: $callId")
|
|
99
121
|
activeCalls[callId]?.state = CallState.HELD
|
|
122
|
+
emitEvent(CallEventType.CALL_HELD, JSONObject().put("callId", callId))
|
|
100
123
|
notifyCallStateChanged(context)
|
|
101
124
|
}
|
|
102
125
|
|
|
126
|
+
fun unholdCall(context: Context, callId: String) {
|
|
127
|
+
Log.d(TAG, "unholdCall: $callId")
|
|
128
|
+
activeCalls[callId]?.state = CallState.ACTIVE
|
|
129
|
+
emitEvent(CallEventType.CALL_UNHELD, JSONObject().put("callId", callId))
|
|
130
|
+
notifyCallStateChanged(context)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
fun muteCall(context: Context, callId: String) {
|
|
134
|
+
emitEvent(CallEventType.CALL_MUTED, JSONObject().put("callId", callId))
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
fun unmuteCall(context: Context, callId: String) {
|
|
138
|
+
emitEvent(CallEventType.CALL_UNMUTED, JSONObject().put("callId", callId))
|
|
139
|
+
}
|
|
140
|
+
|
|
103
141
|
fun endCall(context: Context, callId: String) {
|
|
104
142
|
Log.d(TAG, "endCall: $callId")
|
|
105
143
|
activeCalls[callId]?.state = CallState.ENDED
|
|
@@ -110,13 +148,21 @@ object CallEngine {
|
|
|
110
148
|
cancelIncomingCallUI(context)
|
|
111
149
|
stopForegroundService(context)
|
|
112
150
|
disconnectTelecomCall(context, callId)
|
|
151
|
+
emitEvent(CallEventType.CALL_ENDED, JSONObject().put("callId", callId))
|
|
113
152
|
notifyCallStateChanged(context)
|
|
114
153
|
}
|
|
115
154
|
|
|
116
155
|
fun endAllCalls(context: Context) {
|
|
117
|
-
|
|
156
|
+
if (activeCalls.isEmpty()) {
|
|
157
|
+
Log.d(TAG, "endAllCalls: No active calls, nothing to do.")
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
Log.d(TAG, "endAllCalls: Ending all active calls.")
|
|
118
161
|
activeCalls.keys.toList().forEach { endCall(context, it) }
|
|
162
|
+
activeCalls.clear()
|
|
119
163
|
currentCallId = null
|
|
164
|
+
cancelIncomingCallUI(context)
|
|
165
|
+
stopForegroundService(context)
|
|
120
166
|
notifyCallStateChanged(context)
|
|
121
167
|
}
|
|
122
168
|
|
|
@@ -195,7 +241,6 @@ object CallEngine {
|
|
|
195
241
|
}
|
|
196
242
|
|
|
197
243
|
fun disconnectTelecomCall(context: Context, callId: String?) {
|
|
198
|
-
// You can extend this to track and disconnect specific calls if needed.
|
|
199
244
|
Log.d(TAG, "disconnectTelecomCall called for callId=$callId")
|
|
200
245
|
}
|
|
201
246
|
|
|
@@ -207,26 +252,95 @@ object CallEngine {
|
|
|
207
252
|
Log.d(TAG, "App brought to foreground via launchIntent")
|
|
208
253
|
}
|
|
209
254
|
|
|
210
|
-
// ---
|
|
255
|
+
// --- Audio Device Management ---
|
|
211
256
|
|
|
212
|
-
fun
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
257
|
+
fun getAudioDevices(context: Context): List<String> {
|
|
258
|
+
audioManager = audioManager ?: context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
|
259
|
+
val devices = mutableListOf<String>()
|
|
260
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
261
|
+
audioManager?.getDevices(AudioManager.GET_DEVICES_OUTPUTS)?.forEach { device ->
|
|
262
|
+
when (device.type) {
|
|
263
|
+
AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, AudioDeviceInfo.TYPE_BLUETOOTH_SCO -> devices.add("Bluetooth")
|
|
264
|
+
AudioDeviceInfo.TYPE_WIRED_HEADPHONES, AudioDeviceInfo.TYPE_WIRED_HEADSET -> devices.add("Headset")
|
|
265
|
+
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> devices.add("Speaker")
|
|
266
|
+
AudioDeviceInfo.TYPE_BUILTIN_EARPIECE -> devices.add("Earpiece")
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
} else {
|
|
270
|
+
devices.add("Speaker")
|
|
271
|
+
devices.add("Earpiece")
|
|
272
|
+
}
|
|
273
|
+
return devices.distinct()
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
fun setAudioRoute(context: Context, route: String) {
|
|
277
|
+
audioManager = audioManager ?: context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
|
278
|
+
when (route) {
|
|
279
|
+
"Speaker" -> audioManager?.isSpeakerphoneOn = true
|
|
280
|
+
"Earpiece" -> audioManager?.isSpeakerphoneOn = false
|
|
281
|
+
"Bluetooth" -> audioManager?.startBluetoothSco()
|
|
282
|
+
"Headset" -> { /* usually auto-selected */ }
|
|
283
|
+
}
|
|
284
|
+
emitEvent(CallEventType.AUDIO_ROUTE_CHANGED, JSONObject().put("route", route))
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// --- Screen Awake Management ---
|
|
288
|
+
fun keepScreenAwake(context: Context, keepAwake: Boolean) {
|
|
289
|
+
val powerManager = context.getSystemService(Context.POWER_SERVICE) as android.os.PowerManager
|
|
290
|
+
if (keepAwake) {
|
|
291
|
+
if (wakeLock == null || !wakeLock!!.isHeld) {
|
|
292
|
+
wakeLock = powerManager.newWakeLock(
|
|
293
|
+
android.os.PowerManager.SCREEN_DIM_WAKE_LOCK or android.os.PowerManager.ACQUIRE_CAUSES_WAKEUP,
|
|
294
|
+
"CallEngine:WakeLock"
|
|
295
|
+
)
|
|
296
|
+
wakeLock?.acquire()
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
wakeLock?.let {
|
|
300
|
+
if (it.isHeld) it.release()
|
|
301
|
+
}
|
|
302
|
+
wakeLock = null
|
|
224
303
|
}
|
|
225
304
|
}
|
|
226
305
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
306
|
+
// --- Audio Device Change Listener ---
|
|
307
|
+
private val audioDeviceCallback = object : AudioManager.AudioDeviceCallback() {
|
|
308
|
+
override fun onAudioDevicesAdded(addedDevices: Array<out AudioDeviceInfo>?) {
|
|
309
|
+
emitAudioDevicesChanged()
|
|
310
|
+
}
|
|
311
|
+
override fun onAudioDevicesRemoved(removedDevices: Array<out AudioDeviceInfo>?) {
|
|
312
|
+
emitAudioDevicesChanged()
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
fun registerAudioDeviceCallback(context: Context) {
|
|
317
|
+
audioManager = audioManager ?: context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
|
318
|
+
audioManager?.registerAudioDeviceCallback(audioDeviceCallback, null)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
fun unregisterAudioDeviceCallback(context: Context) {
|
|
322
|
+
audioManager = audioManager ?: context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
|
323
|
+
audioManager?.unregisterAudioDeviceCallback(audioDeviceCallback)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
fun emitAudioDevicesChanged() {
|
|
327
|
+
val devices = getAudioDevices(audioManager!!.context)
|
|
328
|
+
val json = JSONObject().put("devices", JSONArray(devices))
|
|
329
|
+
emitEvent(CallEventType.AUDIO_DEVICES_CHANGED, json)
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// --- Call State Change Notification ---
|
|
333
|
+
private fun notifyCallStateChanged(context: Context) {
|
|
334
|
+
val calls = getActiveCalls()
|
|
335
|
+
val jsonArray = JSONArray()
|
|
336
|
+
calls.forEach {
|
|
337
|
+
val obj = JSONObject()
|
|
338
|
+
obj.put("callId", it.callId)
|
|
339
|
+
obj.put("callData", it.callData)
|
|
340
|
+
obj.put("state", it.state.name)
|
|
341
|
+
jsonArray.put(obj)
|
|
342
|
+
}
|
|
343
|
+
emitEvent(CallEventType.CALL_STATE_CHANGED, JSONObject().put("calls", jsonArray))
|
|
230
344
|
}
|
|
231
345
|
|
|
232
346
|
private fun createNotificationChannel(context: Context) {
|
|
@@ -271,68 +385,4 @@ object CallEngine {
|
|
|
271
385
|
PHONE_ACCOUNT_ID
|
|
272
386
|
)
|
|
273
387
|
}
|
|
274
|
-
|
|
275
|
-
// --- JS/React Native Integration ---
|
|
276
|
-
|
|
277
|
-
private var callStateListener: ((List<CallInfo>) -> Unit)? = null
|
|
278
|
-
|
|
279
|
-
fun setCallStateListener(listener: ((List<CallInfo>) -> Unit)?) {
|
|
280
|
-
callStateListener = listener
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
private fun notifyCallStateChanged(context: Context) {
|
|
284
|
-
callStateListener?.invoke(getActiveCalls())
|
|
285
|
-
// Optionally, send a local broadcast or use DeviceEventEmitter for JS
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
fun getAudioDevices(context: Context): List<String> {
|
|
289
|
-
audioManager = audioManager ?: context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
|
290
|
-
val devices = mutableListOf<String>()
|
|
291
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
292
|
-
audioManager?.getDevices(AudioManager.GET_DEVICES_OUTPUTS)?.forEach { device ->
|
|
293
|
-
when (device.type) {
|
|
294
|
-
AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, AudioDeviceInfo.TYPE_BLUETOOTH_SCO -> devices.add("Bluetooth")
|
|
295
|
-
AudioDeviceInfo.TYPE_WIRED_HEADPHONES, AudioDeviceInfo.TYPE_WIRED_HEADSET -> devices.add("Headset")
|
|
296
|
-
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> devices.add("Speaker")
|
|
297
|
-
AudioDeviceInfo.TYPE_BUILTIN_EARPIECE -> devices.add("Earpiece")
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
} else {
|
|
301
|
-
// Fallback for older devices
|
|
302
|
-
devices.add("Speaker")
|
|
303
|
-
devices.add("Earpiece")
|
|
304
|
-
}
|
|
305
|
-
return devices.distinct()
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
fun setAudioRoute(context: Context, route: String) {
|
|
309
|
-
audioManager = audioManager ?: context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
|
310
|
-
when (route) {
|
|
311
|
-
"Speaker" -> audioManager?.isSpeakerphoneOn = true
|
|
312
|
-
"Earpiece" -> audioManager?.isSpeakerphoneOn = false
|
|
313
|
-
"Bluetooth" -> audioManager?.startBluetoothSco()
|
|
314
|
-
"Headset" -> { /* usually auto-selected */ }
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// --- Screen Awake Management ---
|
|
319
|
-
private var wakeLock: android.os.PowerManager.WakeLock? = null
|
|
320
|
-
|
|
321
|
-
fun keepScreenAwake(context: Context, keepAwake: Boolean) {
|
|
322
|
-
val powerManager = context.getSystemService(Context.POWER_SERVICE) as android.os.PowerManager
|
|
323
|
-
if (keepAwake) {
|
|
324
|
-
if (wakeLock == null || !wakeLock!!.isHeld) {
|
|
325
|
-
wakeLock = powerManager.newWakeLock(
|
|
326
|
-
android.os.PowerManager.SCREEN_DIM_WAKE_LOCK or android.os.PowerManager.ACQUIRE_CAUSES_WAKEUP,
|
|
327
|
-
"CallEngine:WakeLock"
|
|
328
|
-
)
|
|
329
|
-
wakeLock?.acquire()
|
|
330
|
-
}
|
|
331
|
-
} else {
|
|
332
|
-
wakeLock?.let {
|
|
333
|
-
if (it.isHeld) it.release()
|
|
334
|
-
}
|
|
335
|
-
wakeLock = null
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
388
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
package com.qusaieilouti99.callmanager
|
|
2
|
+
|
|
3
|
+
enum class CallEventType {
|
|
4
|
+
INITIAL_CALL_STATE,
|
|
5
|
+
CALL_STATE_CHANGED,
|
|
6
|
+
AUDIO_DEVICES_CHANGED,
|
|
7
|
+
AUDIO_ROUTE_CHANGED,
|
|
8
|
+
CALL_HELD,
|
|
9
|
+
CALL_UNHELD,
|
|
10
|
+
CALL_MUTED,
|
|
11
|
+
CALL_UNMUTED,
|
|
12
|
+
CALL_ANSWERED,
|
|
13
|
+
CALL_REJECTED,
|
|
14
|
+
CALL_ENDED
|
|
15
|
+
}
|
|
@@ -14,26 +14,29 @@ class CallManagerModule(reactContext: ReactApplicationContext) :
|
|
|
14
14
|
const val TAG = "CallManagerModule"
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
// JSI event handler (set from JS)
|
|
18
17
|
private var eventHandler: Callback? = null
|
|
19
18
|
|
|
20
19
|
override fun getName(): String = NAME
|
|
21
20
|
|
|
22
|
-
// JSI event handler registration
|
|
23
21
|
override fun setEventHandler(callback: Callback) {
|
|
24
22
|
Log.d(TAG, "setEventHandler called, registering JS callback")
|
|
25
23
|
eventHandler = callback
|
|
26
|
-
|
|
24
|
+
CallEngine.setEventHandler { eventType, data ->
|
|
25
|
+
eventHandler?.invoke(eventType.name, data)
|
|
26
|
+
}
|
|
27
|
+
// Send initial call state if there is an active call
|
|
28
|
+
val initialCallState = CallEngine.getCurrentCallState()
|
|
29
|
+
if (initialCallState.isNotEmpty()) {
|
|
30
|
+
Log.d(TAG, "Sending initial call state to JS: $initialCallState")
|
|
31
|
+
eventHandler?.invoke(CallEventType.INITIAL_CALL_STATE.name, initialCallState)
|
|
32
|
+
}
|
|
27
33
|
}
|
|
28
34
|
|
|
29
|
-
// JSI event emission (call from CallEngine or anywhere)
|
|
30
35
|
fun emitEvent(event: String, callData: String) {
|
|
31
36
|
Log.d(TAG, "emitEvent: event=$event, callData=$callData")
|
|
32
37
|
eventHandler?.invoke(event, callData)
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
// --- Call control (all JSI, no bridge) ---
|
|
36
|
-
|
|
37
40
|
override fun reportIncomingCall(callId: String, callData: String) {
|
|
38
41
|
Log.d(TAG, "reportIncomingCall called from JS with callId=$callId, callData=$callData")
|
|
39
42
|
CallEngine.reportIncomingCall(reactApplicationContext, callId, callData)
|
|
@@ -61,8 +64,6 @@ class CallManagerModule(reactContext: ReactApplicationContext) :
|
|
|
61
64
|
CallEngine.reportIncomingCall(reactApplicationContext, callId, callData)
|
|
62
65
|
}
|
|
63
66
|
|
|
64
|
-
// --- JSI-native audio/device/screen APIs ---
|
|
65
|
-
|
|
66
67
|
override fun getAudioDevices(): WritableArray {
|
|
67
68
|
val devices = CallEngine.getAudioDevices(reactApplicationContext)
|
|
68
69
|
val array = Arguments.createArray()
|
|
@@ -3,8 +3,8 @@ package com.qusaieilouti99.callmanager
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import android.telecom.Connection
|
|
5
5
|
import android.telecom.DisconnectCause
|
|
6
|
+
import android.telecom.CallAudioState
|
|
6
7
|
import android.util.Log
|
|
7
|
-
import com.facebook.react.ReactApplication
|
|
8
8
|
|
|
9
9
|
class MyConnection(
|
|
10
10
|
private val context: Context,
|
|
@@ -18,14 +18,7 @@ class MyConnection(
|
|
|
18
18
|
override fun onAnswer() {
|
|
19
19
|
Log.d(TAG, "Call answered")
|
|
20
20
|
setActive()
|
|
21
|
-
|
|
22
|
-
(context.applicationContext as? ReactApplication)?.let { app ->
|
|
23
|
-
val module = app.reactNativeHost.reactInstanceManager
|
|
24
|
-
.currentReactContext
|
|
25
|
-
?.getNativeModule(CallManagerModule::class.java)
|
|
26
|
-
module?.emitEvent("onCallAnswered", callData)
|
|
27
|
-
}
|
|
28
|
-
// Bring app to foreground
|
|
21
|
+
CallEngine.answerCall(context, callData)
|
|
29
22
|
CallEngine.bringAppToForeground(context)
|
|
30
23
|
}
|
|
31
24
|
|
|
@@ -33,31 +26,40 @@ class MyConnection(
|
|
|
33
26
|
Log.d(TAG, "Call rejected")
|
|
34
27
|
setDisconnected(DisconnectCause(DisconnectCause.REJECTED))
|
|
35
28
|
destroy()
|
|
36
|
-
(context
|
|
37
|
-
val module = app.reactNativeHost.reactInstanceManager
|
|
38
|
-
.currentReactContext
|
|
39
|
-
?.getNativeModule(CallManagerModule::class.java)
|
|
40
|
-
module?.emitEvent("onCallRejected", callData)
|
|
41
|
-
}
|
|
42
|
-
// Clean up
|
|
43
|
-
CallEngine.cancelIncomingCallUI(context)
|
|
44
|
-
CallEngine.stopForegroundService(context)
|
|
45
|
-
CallEngine.disconnectTelecomCall(context, "")
|
|
29
|
+
CallEngine.endCall(context, callData)
|
|
46
30
|
}
|
|
47
31
|
|
|
48
32
|
override fun onDisconnect() {
|
|
49
33
|
Log.d(TAG, "Call disconnected")
|
|
50
34
|
setDisconnected(DisconnectCause(DisconnectCause.LOCAL))
|
|
51
35
|
destroy()
|
|
52
|
-
(context
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
36
|
+
CallEngine.endCall(context, callData)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override fun onHold() {
|
|
40
|
+
super.onHold()
|
|
41
|
+
Log.d(TAG, "Call held")
|
|
42
|
+
CallEngine.holdCall(context, callData)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override fun onUnhold() {
|
|
46
|
+
super.onUnhold()
|
|
47
|
+
Log.d(TAG, "Call unheld")
|
|
48
|
+
CallEngine.unholdCall(context, callData)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
override fun onCallAudioStateChanged(state: CallAudioState) {
|
|
52
|
+
super.onCallAudioStateChanged(state)
|
|
53
|
+
Log.d(TAG, "Audio state changed: muted=${state.isMuted}, route=${state.route}")
|
|
54
|
+
if (state.isMuted) {
|
|
55
|
+
CallEngine.muteCall(context, callData)
|
|
56
|
+
} else {
|
|
57
|
+
CallEngine.unmuteCall(context, callData)
|
|
57
58
|
}
|
|
58
|
-
//
|
|
59
|
-
CallEngine.
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
// Do NOT emit audio devices changed here; only emit route change
|
|
60
|
+
CallEngine.emitEvent(
|
|
61
|
+
CallEventType.AUDIO_ROUTE_CHANGED,
|
|
62
|
+
org.json.JSONObject().put("route", state.route)
|
|
63
|
+
)
|
|
62
64
|
}
|
|
63
65
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"..\\..\\src","sources":["NativeCallManager.ts"],"mappings":"","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
3
|
+
import { TurboModuleRegistry } from 'react-native';
|
|
4
|
+
const NativeCallManager = TurboModuleRegistry.getEnforcing('CallManager');
|
|
5
|
+
export const reportIncomingCall = NativeCallManager.reportIncomingCall;
|
|
6
|
+
export const endCall = NativeCallManager.endCall;
|
|
7
|
+
export const answerCall = NativeCallManager.answerCall;
|
|
8
|
+
export const silenceRingtone = NativeCallManager.silenceRingtone;
|
|
9
|
+
export const rejectCurrentAndAnswerNew = NativeCallManager.rejectCurrentAndAnswerNew;
|
|
10
|
+
export const setEventHandler = NativeCallManager.setEventHandler;
|
|
11
|
+
export const getAudioDevices = NativeCallManager.getAudioDevices;
|
|
12
|
+
export const setAudioRoute = NativeCallManager.setAudioRoute;
|
|
13
|
+
export const keepScreenAwake = NativeCallManager.keepScreenAwake;
|
|
5
14
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["
|
|
1
|
+
{"version":3,"names":["TurboModuleRegistry","NativeCallManager","getEnforcing","reportIncomingCall","endCall","answerCall","silenceRingtone","rejectCurrentAndAnswerNew","setEventHandler","getAudioDevices","setAudioRoute","keepScreenAwake"],"sourceRoot":"..\\..\\src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,mBAAmB,QAAQ,cAAc;AAGlD,MAAMC,iBAAiB,GAAGD,mBAAmB,CAACE,YAAY,CAAO,aAAa,CAAC;AAE/E,OAAO,MAAMC,kBAAkB,GAAGF,iBAAiB,CAACE,kBAAkB;AACtE,OAAO,MAAMC,OAAO,GAAGH,iBAAiB,CAACG,OAAO;AAChD,OAAO,MAAMC,UAAU,GAAGJ,iBAAiB,CAACI,UAAU;AACtD,OAAO,MAAMC,eAAe,GAAGL,iBAAiB,CAACK,eAAe;AAChE,OAAO,MAAMC,yBAAyB,GAAGN,iBAAiB,CAACM,yBAAyB;AACpF,OAAO,MAAMC,eAAe,GAAGP,iBAAiB,CAACO,eAAe;AAEhE,OAAO,MAAMC,eAAe,GAAGR,iBAAiB,CAACQ,eAAe;AAChE,OAAO,MAAMC,aAAa,GAAGT,iBAAiB,CAACS,aAAa;AAC5D,OAAO,MAAMC,eAAe,GAAGV,iBAAiB,CAACU,eAAe","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeCallManager.d.ts","sourceRoot":"","sources":["../../../src/NativeCallManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"NativeCallManager.d.ts","sourceRoot":"","sources":["../../../src/NativeCallManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3D,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,eAAe,IAAI,IAAI,CAAC;IACxB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAClE,eAAe,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAG3E,eAAe,IAAI,MAAM,EAAE,CAAC;IAC5B,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,eAAe,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;CAC3C"}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
1
|
+
export declare const reportIncomingCall: (callId: string, callData: string) => void;
|
|
2
|
+
export declare const endCall: (callId: string) => void;
|
|
3
|
+
export declare const answerCall: (callId: string) => void;
|
|
4
|
+
export declare const silenceRingtone: () => void;
|
|
5
|
+
export declare const rejectCurrentAndAnswerNew: (callId: string, callData: string) => void;
|
|
6
|
+
export declare const setEventHandler: (callback: (event: string, callData: string) => void) => void;
|
|
7
|
+
export declare const getAudioDevices: () => string[];
|
|
8
|
+
export declare const setAudioRoute: (route: string) => void;
|
|
9
|
+
export declare const keepScreenAwake: (keepAwake: boolean) => void;
|
|
3
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAKA,eAAO,MAAM,kBAAkB,4CAAuC,CAAC;AACvE,eAAO,MAAM,OAAO,0BAA4B,CAAC;AACjD,eAAO,MAAM,UAAU,0BAA+B,CAAC;AACvD,eAAO,MAAM,eAAe,YAAoC,CAAC;AACjE,eAAO,MAAM,yBAAyB,4CAA8C,CAAC;AACrF,eAAO,MAAM,eAAe,+DAAoC,CAAC;AAEjE,eAAO,MAAM,eAAe,gBAAoC,CAAC;AACjE,eAAO,MAAM,aAAa,yBAAkC,CAAC;AAC7D,eAAO,MAAM,eAAe,8BAAoC,CAAC"}
|
package/package.json
CHANGED
package/src/NativeCallManager.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { TurboModule } from 'react-native';
|
|
2
|
-
import { TurboModuleRegistry } from 'react-native';
|
|
3
2
|
|
|
4
3
|
export interface Spec extends TurboModule {
|
|
5
4
|
reportIncomingCall(callId: string, callData: string): void;
|
|
@@ -14,5 +13,3 @@ export interface Spec extends TurboModule {
|
|
|
14
13
|
setAudioRoute(route: string): void;
|
|
15
14
|
keepScreenAwake(keepAwake: boolean): void;
|
|
16
15
|
}
|
|
17
|
-
|
|
18
|
-
export default TurboModuleRegistry.getEnforcing<Spec>('CallManager');
|
package/src/index.tsx
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { TurboModuleRegistry } from 'react-native';
|
|
2
|
+
import type { Spec } from './NativeCallManager';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
const NativeCallManager = TurboModuleRegistry.getEnforcing<Spec>('CallManager');
|
|
5
|
+
|
|
6
|
+
export const reportIncomingCall = NativeCallManager.reportIncomingCall;
|
|
7
|
+
export const endCall = NativeCallManager.endCall;
|
|
8
|
+
export const answerCall = NativeCallManager.answerCall;
|
|
9
|
+
export const silenceRingtone = NativeCallManager.silenceRingtone;
|
|
10
|
+
export const rejectCurrentAndAnswerNew = NativeCallManager.rejectCurrentAndAnswerNew;
|
|
11
|
+
export const setEventHandler = NativeCallManager.setEventHandler;
|
|
12
|
+
|
|
13
|
+
export const getAudioDevices = NativeCallManager.getAudioDevices;
|
|
14
|
+
export const setAudioRoute = NativeCallManager.setAudioRoute;
|
|
15
|
+
export const keepScreenAwake = NativeCallManager.keepScreenAwake;
|