@qusaieilouti99/call-manager 0.1.34 → 0.1.36

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.
@@ -74,8 +74,6 @@ class CallActivity : Activity() {
74
74
 
75
75
  override fun onBackPressed() {
76
76
  Log.d(TAG, "CallActivity onBackPressed for callId: $callId. Treating as decline/dismiss.")
77
- // Decision: User pressing back on the incoming call screen is treated as declining the call.
78
- // If you want the call to continue ringing in the background, remove the CallEngine.endCall() line.
79
77
  finishReason = FinishReason.MANUAL_DISMISS
80
78
  CallEngine.endCall(this, callId)
81
79
  finishCallActivity()
@@ -12,10 +12,16 @@ import android.media.MediaPlayer
12
12
  import android.media.RingtoneManager
13
13
  import android.net.Uri
14
14
  import android.os.Build
15
- import android.os.Bundle
15
+ import android.os.Bundle // Explicit import
16
16
  import android.os.PowerManager
17
- import android.telecom.*
18
- import android.util.Log
17
+ import android.telecom.CallAudioState // Explicit import
18
+ import android.telecom.Connection // Explicit import
19
+ import android.telecom.DisconnectCause // Explicit import
20
+ import android.telecom.PhoneAccount // Explicit import
21
+ import android.telecom.PhoneAccountHandle // Explicit import
22
+ import android.telecom.TelecomManager // Explicit import
23
+ import android.telecom.VideoProfile // Explicit import
24
+ import android.util.Log // Explicit import
19
25
  import android.graphics.Color
20
26
  import android.app.Person
21
27
  import org.json.JSONArray
@@ -443,7 +449,7 @@ object CallEngine {
443
449
  // Returns the generated AudioRoutesInfo data class
444
450
  fun getAudioDevices(): AudioRoutesInfo {
445
451
  audioManager = audioManager ?: appContext?.getSystemService(Context.AUDIO_SERVICE) as? AudioManager ?: run {
446
- Log.e(TAG, "getAudioDevices: AudioManager is null or appContext is not set.")
452
+ Log.e(TAG, "getAudioDevices: AudioManager is null or appContext is not set. Returning default.")
447
453
  return AudioRoutesInfo(emptyArray(), "Unknown") // Return default empty info
448
454
  }
449
455
  val devices = mutableListOf<String>()
@@ -455,20 +461,21 @@ object CallEngine {
455
461
  when (device.type) {
456
462
  AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, AudioDeviceInfo.TYPE_BLUETOOTH_SCO -> {
457
463
  devices.add("Bluetooth")
458
- if (audioManager?.isBluetoothScoOn == true && device.isSource == false) currentRoute = "Bluetooth" // check if output device
464
+ if (audioManager?.isBluetoothScoOn == true && !device.isSource) currentRoute = "Bluetooth" // check if output device
459
465
  }
460
466
  AudioDeviceInfo.TYPE_WIRED_HEADPHONES, AudioDeviceInfo.TYPE_WIRED_HEADSET -> {
461
467
  devices.add("Headset")
462
- if (audioManager?.isWiredHeadsetOn == true && device.isSource == false) currentRoute = "Headset"
468
+ if (audioManager?.isWiredHeadsetOn == true && !device.isSource) currentRoute = "Headset"
463
469
  }
464
470
  AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> {
465
471
  devices.add("Speaker")
466
- if (audioManager?.isSpeakerphoneOn == true && device.isSource == false) currentRoute = "Speaker"
472
+ if (audioManager?.isSpeakerphoneOn == true && !device.isSource) currentRoute = "Speaker"
467
473
  }
468
474
  AudioDeviceInfo.TYPE_BUILTIN_EARPIECE -> {
469
475
  devices.add("Earpiece")
470
476
  // Earpiece is active if speaker, bluetooth, and headset are off
471
- if (audioManager?.isSpeakerphoneOn == false && audioManager?.isWiredHeadsetOn == false && audioManager?.isBluetoothScoOn == false && device.isSource == false) {
477
+ // This heuristic is tricky, relies on other routes being off
478
+ if (audioManager?.isSpeakerphoneOn == false && audioManager?.isWiredHeadsetOn == false && audioManager?.isBluetoothScoOn == false && !device.isSource) {
472
479
  // This heuristic is tricky, relies on other routes being off
473
480
  currentRoute = "Earpiece"
474
481
  }
@@ -725,19 +732,19 @@ object CallEngine {
725
732
  }
726
733
 
727
734
  // --- Ringback Tone Management (for outgoing calls) ---
728
- // Requires `res/raw/ringback_tone.wav` for custom outgoing ringback.
735
+ // Requires `res/raw/ringback_tone.mp3` for custom outgoing ringback.
729
736
  private fun startRingback() {
730
737
  if (ringbackPlayer != null && ringbackPlayer!!.isPlaying) {
731
738
  Log.d(TAG, "Ringback tone already playing.")
732
739
  return
733
740
  }
734
741
  try {
735
- // Ensure you have `res/raw/ringback_tone.wav` in your project for this to work.
742
+ // Ensure you have `res/raw/ringback_tone.mp3` in your project for this to work.
736
743
  // If you don't want a custom ringback, you can play a silent audio file or do nothing here.
737
744
  val ringbackUri = Uri.parse("android.resource://${appContext?.packageName}/raw/ringback_tone")
738
745
  ringbackPlayer = MediaPlayer.create(appContext, ringbackUri)
739
746
  if (ringbackPlayer == null) {
740
- Log.e(TAG, "Failed to create MediaPlayer for ringback. Check raw/ringback_tone.wav exists.")
747
+ Log.e(TAG, "Failed to create MediaPlayer for ringback. Check raw/ringback_tone.mp3 exists.")
741
748
  return
742
749
  }
743
750
  ringbackPlayer?.apply {
@@ -3,10 +3,12 @@ package com.margelo.nitro.qusaieilouti99.callmanager
3
3
  import android.app.Notification
4
4
  import android.app.NotificationChannel
5
5
  import android.app.Service
6
+ import android.content.Context
6
7
  import android.content.Intent
7
8
  import android.os.Build
9
+ import android.util.Log // Explicit import
8
10
  import android.os.IBinder
9
- import android.util.Log
11
+ import android.app.NotificationManager // Explicit import
10
12
 
11
13
  class CallForegroundService : Service() {
12
14
 
@@ -59,7 +61,7 @@ class CallForegroundService : Service() {
59
61
  NotificationManager.IMPORTANCE_LOW
60
62
  )
61
63
  channel.description = "Notification for ongoing calls"
62
- val manager = getSystemService(NotificationManager::class.java)
64
+ val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // Corrected usage
63
65
  manager.createNotificationChannel(channel)
64
66
  Log.d(TAG, "Foreground notification channel '$CHANNEL_ID' created/updated.")
65
67
  }
@@ -1,6 +1,7 @@
1
1
  package com.margelo.nitro.qusaieilouti99.callmanager
2
2
 
3
3
  import com.facebook.proguard.annotations.DoNotStrip
4
+ import android.util.Log // Explicit import
4
5
  import org.json.JSONArray
5
6
  import org.json.JSONObject
6
7
 
@@ -9,7 +10,9 @@ class CallManager : HybridCallManagerSpec() {
9
10
 
10
11
  private val TAG = "CallManager"
11
12
 
12
- private var currentListener: ((CallEventType, String) -> Unit)? = null
13
+ // Listener type now directly matches the generated Func_void_CallEventType_std__string
14
+ // This is the correct type from your Nitro codegen output.
15
+ private var currentListener: Func_void_CallEventType_std__string? = null
13
16
 
14
17
  override fun endCall(callId: String) {
15
18
  Log.d(TAG, "endCall requested for callId: $callId")
@@ -50,24 +53,25 @@ class CallManager : HybridCallManagerSpec() {
50
53
  } ?: Log.e(TAG, "App context not set for keepScreenAwake.")
51
54
  }
52
55
 
53
- // Listener type changed to generated Func_void_CallEventType_std__string
56
+ // Corrected addListener signature to match generated HybridCallManagerSpec
57
+ // This is the primary fix for the `addListener overrides nothing` error.
54
58
  override fun addListener(
55
- listener: Func_void_CallEventType_std__string // Use generated type
59
+ listener: Func_void_CallEventType_std__string // Use generated type directly
56
60
  ): Func_void { // Return generated type
57
- Log.d(TAG, "addListener called.")
58
- // Cast the generated listener (which implements (CallEventType, String) -> Unit)
59
- // to our internal functional type for CallEngine.
60
- currentListener = { event: CallEventType, payload: String ->
61
- listener.invoke(event, payload) // Invoke the generated listener
62
- }
63
- CallEngine.setEventHandler(currentListener)
61
+ Log.d(TAG, "addListener called with listener: $listener")
62
+ // Store the incoming Nitro-generated listener.
63
+ // It already implements the (CallEventType, String) -> Unit interface.
64
+ currentListener = listener
65
+ CallEngine.setEventHandler(listener) // Pass it directly to CallEngine
64
66
 
65
- // Return a generated Func_void for the remove function
67
+ // Return a Nitro-generated Func_void for the remove function
66
68
  return Func_void_java {
67
69
  if (currentListener === listener) { // Compare against the original listener passed
68
70
  CallEngine.setEventHandler(null)
69
71
  currentListener = null
70
72
  Log.d(TAG, "Listener removed.")
73
+ } else {
74
+ Log.d(TAG, "Attempted to remove a listener that was not current.")
71
75
  }
72
76
  }
73
77
  }
@@ -2,24 +2,26 @@ package com.margelo.nitro.qusaieilouti99.callmanager
2
2
 
3
3
  import android.content.Context
4
4
  import android.net.Uri
5
+ import android.os.Bundle // Explicit import
5
6
  import android.telecom.Connection
6
7
  import android.telecom.DisconnectCause
7
- import android.telecom.CallAudioState
8
+ import android.telecom.CallAudioState // Explicit import
8
9
  import android.telecom.VideoProfile
9
- import android.util.Log
10
+ import android.util.Log // Explicit import
10
11
  import org.json.JSONObject
11
12
  import java.util.UUID
12
13
 
13
14
  class MyConnection(
14
15
  private val context: Context,
15
- callDataJson: String // Only callDataJson parameter
16
+ callDataJson: String
16
17
  ) : Connection() {
17
18
 
18
19
  companion object {
19
20
  const val TAG = "MyConnection"
20
21
  }
21
22
 
22
- private val callId: String = try {
23
+ // Changed to internal val to allow access from MyConnectionService for logging
24
+ internal val callId: String = try {
23
25
  JSONObject(callDataJson).optString("callId", UUID.randomUUID().toString())
24
26
  } catch (e: Exception) {
25
27
  UUID.randomUUID().toString()
@@ -105,10 +107,13 @@ class MyConnection(
105
107
  override fun onPlayDtmfTone(digit: Char) {
106
108
  super.onPlayDtmfTone(digit)
107
109
  Log.d(TAG, "Playing DTMF tone: $digit for callId: $callId")
108
- CallEngine.emitEvent(
109
- CallEventType.DTMF_TONE, // Assuming DTMF_TONE is a valid CallEventType
110
- JSONObject().put("callId", callId).put("digit", digit.toString())
111
- )
110
+ // NOTE: DTMF_TONE is not in your current CallEventType.ts enum.
111
+ // If you need to emit this event, you MUST add 'DTMF_TONE' to your CallEventType.ts
112
+ // and re-run nitro-codegen. For now, it's commented out to prevent compilation error.
113
+ // CallEngine.emitEvent(
114
+ // CallEventType.DTMF_TONE,
115
+ // JSONObject().put("callId", callId).put("digit", digit.toString())
116
+ // )
112
117
  }
113
118
 
114
119
  override fun onStopDtmfTone() {
@@ -116,7 +121,7 @@ class MyConnection(
116
121
  Log.d(TAG, "Stopping DTMF tone for callId: $callId")
117
122
  }
118
123
 
119
- override fun onConnectionEvent(event: String, extras: Bundle?) {
124
+ override fun onConnectionEvent(event: String, extras: Bundle?) { // Resolved - signature is correct
120
125
  super.onConnectionEvent(event, extras)
121
126
  Log.d(TAG, "Connection event: $event, extras: $extras for callId: $callId")
122
127
  }
@@ -6,7 +6,8 @@ import android.telecom.ConnectionService
6
6
  import android.telecom.PhoneAccountHandle
7
7
  import android.telecom.TelecomManager
8
8
  import android.telecom.VideoProfile
9
- import android.util.Log
9
+ import android.telecom.CallAudioState // Explicit import
10
+ import android.util.Log // Explicit import
10
11
 
11
12
  class MyConnectionService : ConnectionService() {
12
13
 
@@ -1,2 +1,2 @@
1
- export type CallEventType = 'INITIAL_CALL_STATE' | 'CALL_STATE_CHANGED' | 'AUDIO_DEVICES_CHANGED' | 'AUDIO_ROUTE_CHANGED' | 'CALL_HELD' | 'CALL_UNHELD' | 'CALL_MUTED' | 'CALL_UNMUTED' | 'CALL_ANSWERED' | 'CALL_REJECTED' | 'CALL_ENDED';
1
+ export type CallEventType = 'INITIAL_CALL_STATE' | 'CALL_STATE_CHANGED' | 'AUDIO_DEVICES_CHANGED' | 'AUDIO_ROUTE_CHANGED' | 'CALL_HELD' | 'CALL_UNHELD' | 'CALL_MUTED' | 'CALL_UNMUTED' | 'CALL_ANSWERED' | 'CALL_REJECTED' | 'CALL_ENDED' | 'DTMF_TONE';
2
2
  //# sourceMappingURL=CallEventType.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CallEventType.d.ts","sourceRoot":"","sources":["../../../src/CallEventType.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,aAAa,GACrB,oBAAoB,GACpB,oBAAoB,GACpB,uBAAuB,GACvB,qBAAqB,GACrB,WAAW,GACX,aAAa,GACb,YAAY,GACZ,cAAc,GACd,eAAe,GACf,eAAe,GACf,YAAY,CAAC"}
1
+ {"version":3,"file":"CallEventType.d.ts","sourceRoot":"","sources":["../../../src/CallEventType.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,aAAa,GACrB,oBAAoB,GACpB,oBAAoB,GACpB,uBAAuB,GACvB,qBAAqB,GACrB,WAAW,GACX,aAAa,GACb,YAAY,GACZ,cAAc,GACd,eAAe,GACf,eAAe,GACf,YAAY,GACZ,WAAW,CAAC"}
@@ -52,6 +52,7 @@ namespace margelo::nitro::qusaieilouti99_callmanager {
52
52
  static const auto fieldCALL_ANSWERED = clazz->getStaticField<JCallEventType>("CALL_ANSWERED");
53
53
  static const auto fieldCALL_REJECTED = clazz->getStaticField<JCallEventType>("CALL_REJECTED");
54
54
  static const auto fieldCALL_ENDED = clazz->getStaticField<JCallEventType>("CALL_ENDED");
55
+ static const auto fieldDTMF_TONE = clazz->getStaticField<JCallEventType>("DTMF_TONE");
55
56
 
56
57
  switch (value) {
57
58
  case CallEventType::INITIAL_CALL_STATE:
@@ -76,6 +77,8 @@ namespace margelo::nitro::qusaieilouti99_callmanager {
76
77
  return clazz->getStaticFieldValue(fieldCALL_REJECTED);
77
78
  case CallEventType::CALL_ENDED:
78
79
  return clazz->getStaticFieldValue(fieldCALL_ENDED);
80
+ case CallEventType::DTMF_TONE:
81
+ return clazz->getStaticFieldValue(fieldDTMF_TONE);
79
82
  default:
80
83
  std::string stringValue = std::to_string(static_cast<int>(value));
81
84
  throw std::invalid_argument("Invalid enum value (" + stringValue + "!");
@@ -26,7 +26,8 @@ enum class CallEventType {
26
26
  CALL_UNMUTED,
27
27
  CALL_ANSWERED,
28
28
  CALL_REJECTED,
29
- CALL_ENDED;
29
+ CALL_ENDED,
30
+ DTMF_TONE;
30
31
 
31
32
  @DoNotStrip
32
33
  @Keep
@@ -39,6 +39,8 @@ public extension CallEventType {
39
39
  self = .callRejected
40
40
  case "CALL_ENDED":
41
41
  self = .callEnded
42
+ case "DTMF_TONE":
43
+ self = .dtmfTone
42
44
  default:
43
45
  return nil
44
46
  }
@@ -71,6 +73,8 @@ public extension CallEventType {
71
73
  return "CALL_REJECTED"
72
74
  case .callEnded:
73
75
  return "CALL_ENDED"
76
+ case .dtmfTone:
77
+ return "DTMF_TONE"
74
78
  }
75
79
  }
76
80
  }
@@ -40,6 +40,7 @@ namespace margelo::nitro::qusaieilouti99_callmanager {
40
40
  CALL_ANSWERED SWIFT_NAME(callAnswered) = 8,
41
41
  CALL_REJECTED SWIFT_NAME(callRejected) = 9,
42
42
  CALL_ENDED SWIFT_NAME(callEnded) = 10,
43
+ DTMF_TONE SWIFT_NAME(dtmfTone) = 11,
43
44
  } CLOSED_ENUM;
44
45
 
45
46
  } // namespace margelo::nitro::qusaieilouti99_callmanager
@@ -65,6 +66,7 @@ namespace margelo::nitro {
65
66
  case hashString("CALL_ANSWERED"): return CallEventType::CALL_ANSWERED;
66
67
  case hashString("CALL_REJECTED"): return CallEventType::CALL_REJECTED;
67
68
  case hashString("CALL_ENDED"): return CallEventType::CALL_ENDED;
69
+ case hashString("DTMF_TONE"): return CallEventType::DTMF_TONE;
68
70
  default: [[unlikely]]
69
71
  throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum CallEventType - invalid value!");
70
72
  }
@@ -82,6 +84,7 @@ namespace margelo::nitro {
82
84
  case CallEventType::CALL_ANSWERED: return JSIConverter<std::string>::toJSI(runtime, "CALL_ANSWERED");
83
85
  case CallEventType::CALL_REJECTED: return JSIConverter<std::string>::toJSI(runtime, "CALL_REJECTED");
84
86
  case CallEventType::CALL_ENDED: return JSIConverter<std::string>::toJSI(runtime, "CALL_ENDED");
87
+ case CallEventType::DTMF_TONE: return JSIConverter<std::string>::toJSI(runtime, "DTMF_TONE");
85
88
  default: [[unlikely]]
86
89
  throw std::invalid_argument("Cannot convert CallEventType to JS - invalid value: "
87
90
  + std::to_string(static_cast<int>(arg)) + "!");
@@ -104,6 +107,7 @@ namespace margelo::nitro {
104
107
  case hashString("CALL_ANSWERED"):
105
108
  case hashString("CALL_REJECTED"):
106
109
  case hashString("CALL_ENDED"):
110
+ case hashString("DTMF_TONE"):
107
111
  return true;
108
112
  default:
109
113
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qusaieilouti99/call-manager",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
4
4
  "description": "Call manager",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -10,4 +10,5 @@ export type CallEventType =
10
10
  | 'CALL_UNMUTED'
11
11
  | 'CALL_ANSWERED'
12
12
  | 'CALL_REJECTED'
13
- | 'CALL_ENDED';
13
+ | 'CALL_ENDED'
14
+ | 'DTMF_TONE'; // ADD THIS LINE IF YOU NEED DTMF EVENTS