@qusaieilouti99/call-manager 0.1.69 → 0.1.71
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.
|
@@ -30,9 +30,6 @@ import android.telecom.PhoneAccountHandle
|
|
|
30
30
|
import android.telecom.TelecomManager
|
|
31
31
|
import android.telecom.VideoProfile
|
|
32
32
|
import android.util.Log
|
|
33
|
-
import kotlinx.coroutines.CoroutineScope
|
|
34
|
-
import kotlinx.coroutines.Dispatchers
|
|
35
|
-
import kotlinx.coroutines.launch
|
|
36
33
|
import org.json.JSONArray
|
|
37
34
|
import org.json.JSONObject
|
|
38
35
|
import java.util.concurrent.ConcurrentHashMap
|
|
@@ -275,8 +272,11 @@ object CallEngine {
|
|
|
275
272
|
|
|
276
273
|
val isVideoCall = callType == "Video"
|
|
277
274
|
if (!canMakeMultipleCalls && activeCalls.isNotEmpty()) {
|
|
278
|
-
activeCalls.values.
|
|
279
|
-
|
|
275
|
+
activeCalls.values.forEach {
|
|
276
|
+
if (it.state == CallState.ACTIVE) {
|
|
277
|
+
holdCallInternal(it.callId, heldBySystem = false)
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
280
|
}
|
|
281
281
|
|
|
282
282
|
// Track dialing state
|
|
@@ -653,14 +653,16 @@ object CallEngine {
|
|
|
653
653
|
AudioDeviceInfo.TYPE_WIRED_HEADPHONES, AudioDeviceInfo.TYPE_WIRED_HEADSET -> {
|
|
654
654
|
devices.add("Headset")
|
|
655
655
|
}
|
|
656
|
-
// Speaker and Earpiece already added above
|
|
656
|
+
// Speaker and Earpiece already added above if they are reported, but explicit add handles cases where they are not
|
|
657
657
|
}
|
|
658
658
|
}
|
|
659
659
|
} else {
|
|
660
660
|
// For older versions, check for Bluetooth and Headset
|
|
661
|
+
@Suppress("DEPRECATION")
|
|
661
662
|
if (audioManager?.isBluetoothA2dpOn == true || audioManager?.isBluetoothScoOn == true) {
|
|
662
663
|
devices.add("Bluetooth")
|
|
663
664
|
}
|
|
665
|
+
@Suppress("DEPRECATION")
|
|
664
666
|
if (audioManager?.isWiredHeadsetOn == true) {
|
|
665
667
|
devices.add("Headset")
|
|
666
668
|
}
|
|
@@ -669,6 +671,9 @@ object CallEngine {
|
|
|
669
671
|
val currentRoute = getCurrentAudioRoute()
|
|
670
672
|
Log.d(TAG, "Available audio devices: ${devices.toList()}, current route: $currentRoute")
|
|
671
673
|
|
|
674
|
+
// Update last known audio routes info
|
|
675
|
+
lastAudioRoutesInfo = AudioRoutesInfo(devices.toTypedArray(), currentRoute)
|
|
676
|
+
|
|
672
677
|
return AudioRoutesInfo(devices.toTypedArray(), currentRoute)
|
|
673
678
|
}
|
|
674
679
|
|
|
@@ -715,23 +720,6 @@ object CallEngine {
|
|
|
715
720
|
}
|
|
716
721
|
}
|
|
717
722
|
|
|
718
|
-
val newRoute = getCurrentAudioRoute()
|
|
719
|
-
if (previousRoute != newRoute) {
|
|
720
|
-
emitEvent(CallEventType.AUDIO_ROUTE_CHANGED, JSONObject().put("route", newRoute))
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
// UNIFIED event emission - always sends full audio context
|
|
725
|
-
private fun emitAudioRouteChanged() {
|
|
726
|
-
val audioInfo = getAudioDevices()
|
|
727
|
-
val jsonPayload = JSONObject().apply {
|
|
728
|
-
put("devices", JSONArray(audioInfo.devices.toList()))
|
|
729
|
-
put("currentRoute", audioInfo.currentRoute)
|
|
730
|
-
}
|
|
731
|
-
emitEvent(CallEventType.AUDIO_ROUTE_CHANGED, jsonPayload)
|
|
732
|
-
Log.d(TAG, "Audio route changed: ${audioInfo.currentRoute}, available: ${audioInfo.devices.toList()}")
|
|
733
|
-
}
|
|
734
|
-
|
|
735
723
|
private fun getCurrentAudioRoute(): String {
|
|
736
724
|
return when {
|
|
737
725
|
audioManager?.isBluetoothScoOn == true -> "Bluetooth"
|
|
@@ -742,7 +730,7 @@ object CallEngine {
|
|
|
742
730
|
}
|
|
743
731
|
|
|
744
732
|
private fun setInitialAudioRoute(callType: String) {
|
|
745
|
-
val availableDevices = getAudioDevices()
|
|
733
|
+
val availableDevices = getAudioDevices() // This will update lastAudioRoutesInfo
|
|
746
734
|
|
|
747
735
|
val defaultRoute = when {
|
|
748
736
|
availableDevices.devices.contains("Bluetooth") -> "Bluetooth"
|
|
@@ -770,7 +758,19 @@ object CallEngine {
|
|
|
770
758
|
}
|
|
771
759
|
}
|
|
772
760
|
|
|
773
|
-
//
|
|
761
|
+
// UNIFIED event emission - always sends full audio context
|
|
762
|
+
private fun emitAudioRouteChanged() {
|
|
763
|
+
// Re-calculate latest state to ensure accuracy
|
|
764
|
+
val audioInfo = getAudioDevices() // This updates lastAudioRoutesInfo internally
|
|
765
|
+
val jsonPayload = JSONObject().apply {
|
|
766
|
+
put("devices", JSONArray(audioInfo.devices.toList()))
|
|
767
|
+
put("currentRoute", audioInfo.currentRoute)
|
|
768
|
+
}
|
|
769
|
+
emitEvent(CallEventType.AUDIO_ROUTE_CHANGED, jsonPayload)
|
|
770
|
+
Log.d(TAG, "Audio route changed: ${audioInfo.currentRoute}, available: ${audioInfo.devices.toList()}")
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// --- Audio Device Callback ---
|
|
774
774
|
private val audioDeviceCallback = object : AudioDeviceCallback() {
|
|
775
775
|
override fun onAudioDevicesAdded(addedDevices: Array<out AudioDeviceInfo>?) {
|
|
776
776
|
Log.d(TAG, "Audio devices added")
|
|
@@ -783,9 +783,10 @@ object CallEngine {
|
|
|
783
783
|
}
|
|
784
784
|
}
|
|
785
785
|
|
|
786
|
-
//
|
|
786
|
+
// Event for when physical devices are added/removed - includes full audio context
|
|
787
787
|
private fun emitAudioDevicesChanged() {
|
|
788
|
-
|
|
788
|
+
// Re-calculate latest state to ensure accuracy
|
|
789
|
+
val audioInfo = getAudioDevices() // This updates lastAudioRoutesInfo internally
|
|
789
790
|
val jsonPayload = JSONObject().apply {
|
|
790
791
|
put("devices", JSONArray(audioInfo.devices.toList()))
|
|
791
792
|
put("currentRoute", audioInfo.currentRoute)
|
|
@@ -794,6 +795,7 @@ object CallEngine {
|
|
|
794
795
|
Log.d(TAG, "Audio devices changed: available: ${audioInfo.devices.toList()}")
|
|
795
796
|
}
|
|
796
797
|
|
|
798
|
+
|
|
797
799
|
fun registerAudioDeviceCallback() {
|
|
798
800
|
val context = requireContext()
|
|
799
801
|
audioManager = audioManager ?: context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
|
@@ -994,7 +996,35 @@ object CallEngine {
|
|
|
994
996
|
startForegroundService() // Just restart the service with updated info
|
|
995
997
|
}
|
|
996
998
|
|
|
999
|
+
private fun isMainActivityInForeground(): Boolean {
|
|
1000
|
+
val context = requireContext()
|
|
1001
|
+
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
|
1002
|
+
|
|
1003
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
1004
|
+
val tasks = activityManager.getAppTasks()
|
|
1005
|
+
if (tasks.isNotEmpty()) {
|
|
1006
|
+
val taskInfo = tasks[0].taskInfo
|
|
1007
|
+
return taskInfo.topActivity?.className?.contains("MainActivity") == true
|
|
1008
|
+
}
|
|
1009
|
+
} else {
|
|
1010
|
+
@Suppress("DEPRECATION")
|
|
1011
|
+
val tasks = activityManager.getRunningTasks(1)
|
|
1012
|
+
if (tasks.isNotEmpty()) {
|
|
1013
|
+
return tasks[0].topActivity?.className?.contains("MainActivity") == true
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
return false
|
|
1017
|
+
}
|
|
1018
|
+
|
|
997
1019
|
private fun bringAppToForeground() {
|
|
1020
|
+
// Check if MainActivity is already in foreground
|
|
1021
|
+
if (isMainActivityInForeground()) {
|
|
1022
|
+
Log.d(TAG, "MainActivity is already in foreground, skipping bringAppToForeground()")
|
|
1023
|
+
return
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
Log.d(TAG, "MainActivity is not in foreground, bringing to foreground")
|
|
1027
|
+
|
|
998
1028
|
val context = requireContext()
|
|
999
1029
|
val packageName = context.packageName
|
|
1000
1030
|
val launchIntent = context.packageManager.getLaunchIntentForPackage(packageName)
|
|
@@ -25,8 +25,8 @@ class MyConnection(
|
|
|
25
25
|
init {
|
|
26
26
|
connectionProperties = Connection.PROPERTY_SELF_MANAGED
|
|
27
27
|
connectionCapabilities = Connection.CAPABILITY_SUPPORT_HOLD or
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
Connection.CAPABILITY_MUTE or
|
|
29
|
+
Connection.CAPABILITY_HOLD
|
|
30
30
|
|
|
31
31
|
if (callType == "Video") {
|
|
32
32
|
Log.d(TAG, "MyConnection for callId $callId initialized as VIDEO call.")
|
|
@@ -84,11 +84,11 @@ class MyConnection(
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
// Only
|
|
87
|
+
// Only react to route change if it's different.
|
|
88
|
+
// DO NOT emit AUDIO_ROUTE_CHANGED from here, let CallEngine's
|
|
89
|
+
// AudioDeviceCallback handle it for consistency and to avoid duplication.
|
|
88
90
|
if (lastAudioState == null || lastAudioState!!.route != state.route) {
|
|
89
|
-
|
|
90
|
-
// The system audio state change will be detected by CallEngine's audio management
|
|
91
|
-
Log.d(TAG, "System audio route changed to: ${state.route} for callId: $callId")
|
|
91
|
+
Log.d(TAG, "System audio route changed for callId: $callId. Telecom route: ${state.route}")
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
lastAudioState = state
|