@qusaieilouti99/call-manager 0.1.43 → 0.1.44

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.
@@ -1,4 +1,5 @@
1
1
  package com.margelo.nitro.qusaieilouti99.callmanager
2
+
2
3
  import android.app.Activity
3
4
  import android.content.Intent
4
5
  import android.os.Build
@@ -48,7 +49,8 @@ class CallActivity : Activity() {
48
49
  callType = intent.getStringExtra("callType") ?: "Audio"
49
50
  Log.d(TAG, "CallActivity received callId: $callId, callType: $callType")
50
51
 
51
- CallEngine.cancelIncomingCallUI(this)
52
+ // Cancel incoming call UI immediately when CallActivity shows
53
+ // This is handled in the core answer function now
52
54
 
53
55
  val callerName = intent.getStringExtra("callerName") ?: "Unknown"
54
56
  val nameView = findViewById<TextView>(R.id.caller_name)
@@ -60,7 +62,9 @@ class CallActivity : Activity() {
60
62
  answerBtn.setOnClickListener {
61
63
  Log.d(TAG, "CallActivity: Answer button clicked for callId: $callId")
62
64
  finishReason = FinishReason.ANSWER
63
- CallEngine.bringAppToForeground(this)
65
+
66
+ // Use the single core answer function
67
+ CallEngine.answerCall(this, callId)
64
68
  finishCallActivity()
65
69
  }
66
70
 
@@ -78,7 +82,7 @@ class CallActivity : Activity() {
78
82
  super.onDestroy()
79
83
  Log.d(TAG, "CallActivity onDestroy for callId: $callId. Reason: $finishReason")
80
84
  timeoutHandler.removeCallbacks(timeoutRunnable)
81
- CallEngine.stopRingtone()
85
+ // Don't stop ringtone here - it's handled in the core functions
82
86
  }
83
87
 
84
88
  override fun onBackPressed() {
@@ -28,6 +28,7 @@ import org.json.JSONArray
28
28
  import org.json.JSONObject
29
29
  import java.util.UUID
30
30
  import java.util.concurrent.ConcurrentHashMap
31
+ import android.view.WindowManager
31
32
 
32
33
  object CallEngine {
33
34
  private const val TAG = "CallEngine"
@@ -174,7 +175,6 @@ object CallEngine {
174
175
  notifyCallStateChanged(context)
175
176
  }
176
177
 
177
- // CORRECTED: Uses TelecomManager.placeCall for outgoing calls.
178
178
  fun startOutgoingCall(context: Context, callId: String, callData: String) {
179
179
  appContext = context.applicationContext
180
180
  Log.d(TAG, "startOutgoingCall: $callId, $callData")
@@ -218,7 +218,7 @@ object CallEngine {
218
218
  startForegroundService(context)
219
219
  Log.d(TAG, "Successfully reported outgoing call to TelecomManager via placeCall for $callId")
220
220
  startRingback()
221
- bringAppToForeground(context)
221
+ // Don't bring app to foreground here - wait for answer
222
222
  keepScreenAwake(context, true)
223
223
  if (parsedCallType == "Video") {
224
224
  setAudioRoute(context, "Speaker")
@@ -235,33 +235,54 @@ object CallEngine {
235
235
  notifyCallStateChanged(context)
236
236
  }
237
237
 
238
- fun callAnsweredFromJS(context: Context, callId: String) {
239
- Log.d(TAG, "callAnsweredFromJS: $callId - remote party answered")
238
+ // *** SINGLE SOURCE OF TRUTH: Core Answer Function ***
239
+ private fun coreAnswerCall(context: Context, callId: String, isLocalAnswer: Boolean) {
240
+ Log.d(TAG, "coreAnswerCall: $callId, isLocalAnswer: $isLocalAnswer")
241
+
242
+ // Stop all notification sounds and UI immediately
243
+ stopRingtone()
240
244
  stopRingback()
245
+ cancelIncomingCallUI(context)
246
+
247
+ // Update call state
241
248
  activeCalls[callId]?.state = CallState.ACTIVE
242
249
  currentCallId = callId
250
+
251
+ // Handle multi-call scenario
243
252
  if (!canMakeMultipleCalls) {
244
253
  activeCalls.filter { it.key != callId }.values.forEach { it.state = CallState.HELD }
245
254
  }
246
- notifyCallStateChanged(context)
255
+
256
+ // Emit event
247
257
  emitEvent(CallEventType.CALL_ANSWERED, JSONObject().put("callId", callId))
258
+
259
+ // Start foreground service if not already started
260
+ startForegroundService(context)
261
+
262
+ // Wake up screen and clear lock screen if needed
248
263
  keepScreenAwake(context, true)
264
+
265
+ // Bring app to foreground NOW (not earlier)
266
+ bringAppToForeground(context)
267
+
268
+ // Reset audio mode
249
269
  resetAudioMode(context)
270
+
271
+ // Notify state change
272
+ notifyCallStateChanged(context)
273
+
274
+ Log.d(TAG, "coreAnswerCall completed for $callId")
275
+ }
276
+
277
+ // Public answer methods that delegate to the core function
278
+ fun callAnsweredFromJS(context: Context, callId: String) {
279
+ Log.d(TAG, "callAnsweredFromJS: $callId - remote party answered")
280
+ coreAnswerCall(context, callId, false)
250
281
  }
251
282
 
252
283
  fun answerCall(context: Context, callId: String) {
253
284
  Log.d(TAG, "answerCall: $callId - local party answering")
254
- stopRingtone()
255
- activeCalls[callId]?.state = CallState.ACTIVE
256
- currentCallId = callId
257
- if (!canMakeMultipleCalls) {
258
- activeCalls.filter { it.key != callId }.values.forEach { it.state = CallState.HELD }
259
- }
260
- emitEvent(CallEventType.CALL_ANSWERED, JSONObject().put("callId", callId))
261
- notifyCallStateChanged(context)
262
- startForegroundService(context)
263
- keepScreenAwake(context, true)
264
- resetAudioMode(context)
285
+ coreAnswerCall(context, callId, true)
265
286
  }
266
287
 
267
288
  fun holdCall(context: Context, callId: String) {
@@ -327,6 +348,7 @@ object CallEngine {
327
348
  stopForegroundService(context)
328
349
  keepScreenAwake(context, false)
329
350
  resetAudioMode(context)
351
+ clearLockScreenBypass(context) // Clear lock screen bypass when all calls end
330
352
  } else {
331
353
  Log.d(TAG, "Other calls still active. Foreground service remains.")
332
354
  }
@@ -353,6 +375,7 @@ object CallEngine {
353
375
  stopRingback()
354
376
  keepScreenAwake(context, false)
355
377
  resetAudioMode(context)
378
+ clearLockScreenBypass(context) // Clear lock screen bypass
356
379
  notifyCallStateChanged(context)
357
380
  }
358
381
 
@@ -360,6 +383,34 @@ object CallEngine {
360
383
  fun getCurrentCallId(): String? = currentCallId
361
384
  fun isCallActive(): Boolean = activeCalls.any { it.value.state == CallState.ACTIVE || it.value.state == CallState.INCOMING || it.value.state == CallState.DIALING }
362
385
 
386
+ // --- Clear Lock Screen Bypass ---
387
+ private fun clearLockScreenBypass(context: Context) {
388
+ Log.d(TAG, "Clearing lock screen bypass for all activities.")
389
+
390
+ // Send broadcast to MainActivity to clear flags if it's active
391
+ val intent = Intent("com.pingme2022.CLEAR_LOCK_SCREEN_BYPASS")
392
+ context.sendBroadcast(intent)
393
+
394
+ // Also try to clear on the app context activities
395
+ try {
396
+ if (context is Activity) {
397
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
398
+ (context as Activity).setShowWhenLocked(false)
399
+ (context as Activity).setTurnScreenOn(false)
400
+ } else {
401
+ context.window.clearFlags(
402
+ WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
403
+ WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
404
+ WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
405
+ )
406
+ }
407
+ Log.d(TAG, "Cleared lock screen bypass flags from activity context.")
408
+ }
409
+ } catch (e: Exception) {
410
+ Log.w(TAG, "Could not clear lock screen bypass from activity context: ${e.message}")
411
+ }
412
+ }
413
+
363
414
  // --- Notification/UI/Foreground ---
364
415
 
365
416
  fun showIncomingCallUI(context: Context, callId: String, callerName: String, callType: String) {
@@ -443,10 +494,8 @@ object CallEngine {
443
494
  val launchIntent = context.packageManager.getLaunchIntentForPackage(packageName)
444
495
  launchIntent?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
445
496
 
446
- // The deprecated lock screen flags have been removed
447
- // Lock screen bypass is now handled in the target activity (CallActivity, MainActivity)
448
497
  if (isCallActive()) {
449
- Log.d(TAG, "App brought to foreground due to active call - lock screen handling in target activity")
498
+ Log.d(TAG, "App brought to foreground due to active call")
450
499
  } else {
451
500
  Log.d(TAG, "App brought to foreground via normal launchIntent")
452
501
  }
@@ -454,8 +503,10 @@ object CallEngine {
454
503
  context.startActivity(launchIntent)
455
504
  }
456
505
 
457
- // --- Audio Device Management ---
506
+ // Rest of the methods remain the same...
507
+ // [Audio Device Management, Screen Awake Management, etc. - keeping existing implementations]
458
508
 
509
+ // --- Audio Device Management ---
459
510
  fun getAudioDevices(): AudioRoutesInfo {
460
511
  audioManager = appContext?.getSystemService(Context.AUDIO_SERVICE) as? AudioManager ?: run {
461
512
  Log.e(TAG, "getAudioDevices: AudioManager is null or appContext is not set. Returning default.")
@@ -589,7 +640,9 @@ object CallEngine {
589
640
  }
590
641
  }
591
642
 
592
- // --- Audio Device Change Listener ---
643
+ // Continue with rest of existing methods...
644
+ // [Audio Device Change Listener, Call State Change Notification, etc.]
645
+
593
646
  private val audioDeviceCallback = object : AudioDeviceCallback() {
594
647
  override fun onAudioDevicesAdded(addedDevices: Array<out AudioDeviceInfo>?) {
595
648
  Log.d(TAG, "Audio devices added. Emitting AUDIO_DEVICES_CHANGED.")
@@ -627,7 +680,6 @@ object CallEngine {
627
680
  emitEvent(CallEventType.AUDIO_DEVICES_CHANGED, jsonPayload)
628
681
  }
629
682
 
630
- // --- Call State Change Notification ---
631
683
  private fun notifyCallStateChanged(context: Context) {
632
684
  val calls = getActiveCalls()
633
685
  val jsonArray = JSONArray()
@@ -673,7 +725,6 @@ object CallEngine {
673
725
  }
674
726
  }
675
727
 
676
- // PhoneAccount registration is used for both INCOMING and OUTGOING calls when interacting with Telecom
677
728
  private fun registerPhoneAccount(context: Context) {
678
729
  val telecomManager = context.getSystemService(Context.TELECOM_SERVICE) as TelecomManager
679
730
  val phoneAccountHandle = getPhoneAccountHandle(context)
@@ -701,7 +752,6 @@ object CallEngine {
701
752
  )
702
753
  }
703
754
 
704
- // --- Ringtone Management (for incoming calls, pre-Android S) ---
705
755
  fun playRingtone(context: Context) {
706
756
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
707
757
  Log.d(TAG, "playRingtone: Android S+ detected, system will handle ringtone via Telecom.")
@@ -733,7 +783,6 @@ object CallEngine {
733
783
  ringtone = null
734
784
  }
735
785
 
736
- // --- Ringback Tone Management (for outgoing calls) ---
737
786
  private fun startRingback() {
738
787
  if (ringbackPlayer != null && ringbackPlayer!!.isPlaying) {
739
788
  Log.d(TAG, "Ringback tone already playing.")
@@ -15,21 +15,10 @@ class CallNotificationActionReceiver : BroadcastReceiver() {
15
15
 
16
16
  when (intent.action) {
17
17
  "com.qusaieilouti99.callmanager.ANSWER_CALL" -> {
18
- Log.d(TAG, "Answer action received for callId: $callId. Answering call via Telecom.")
18
+ Log.d(TAG, "Answer action received for callId: $callId. Using single core answer function.")
19
19
 
20
- // Get the telecom connection and answer it
21
- val connection = CallEngine.getTelecomConnection(callId)
22
- if (connection != null) {
23
- // This will trigger MyConnection.onAnswer() which handles the rest
24
- connection.onAnswer()
25
- Log.d(TAG, "Call answered via Telecom connection for callId: $callId")
26
- } else {
27
- Log.e(TAG, "No Telecom connection found for callId: $callId. Falling back to direct answer.")
28
- // Fallback: answer directly via CallEngine
29
- CallEngine.answerCall(context, callId)
30
- }
31
-
32
- CallEngine.bringAppToForeground(context)
20
+ // Use the single core answer function instead of multiple pathways
21
+ CallEngine.answerCall(context, callId)
33
22
  }
34
23
  "com.qusaieilouti99.callmanager.DECLINE_CALL" -> {
35
24
  Log.d(TAG, "Decline action received for callId: $callId. Ending call.")
@@ -34,7 +34,7 @@ class MyConnection(
34
34
 
35
35
  // Set connection properties and capabilities
36
36
  connectionProperties = Connection.PROPERTY_SELF_MANAGED
37
- connectionCapabilities = Connection.CAPABILITY_SUPPORT_HOLD or Connection.CAPABILITY_MUTE // Added hold and mute capabilities
37
+ connectionCapabilities = Connection.CAPABILITY_SUPPORT_HOLD or Connection.CAPABILITY_MUTE
38
38
 
39
39
  if (currentCallType == "Video") {
40
40
  Log.d(TAG, "MyConnection for callId $callId initialized as VIDEO call.")
@@ -51,8 +51,9 @@ class MyConnection(
51
51
  override fun onAnswer() {
52
52
  Log.d(TAG, "Call answered via Telecom for callId: $callId")
53
53
  setActive()
54
+
55
+ // Use the single core answer function
54
56
  CallEngine.answerCall(context, callId)
55
- CallEngine.bringAppToForeground(context)
56
57
  }
57
58
 
58
59
  override fun onReject() {
@@ -108,9 +109,6 @@ class MyConnection(
108
109
  override fun onPlayDtmfTone(digit: Char) {
109
110
  super.onPlayDtmfTone(digit)
110
111
  Log.d(TAG, "Playing DTMF tone: $digit for callId: $callId")
111
- // NOTE: DTMF_TONE is not in your current CallEventType enum.
112
- // If you need to emit this event, you MUST add 'DTMF_TONE' to your CallEventType.ts
113
- // and re-run nitro-codegen. For now, it's commented out to prevent compilation error.
114
112
  CallEngine.emitEvent(
115
113
  CallEventType.DTMF_TONE,
116
114
  JSONObject().put("callId", callId).put("digit", digit.toString())
@@ -122,12 +120,10 @@ class MyConnection(
122
120
  Log.d(TAG, "Stopping DTMF tone for callId: $callId")
123
121
  }
124
122
 
125
- // REMOVED: onConnectionEvent override since it doesn't exist in the base Connection class
126
- // If you need connection events, you can send them via sendConnectionEvent() method
127
-
128
123
  override fun onShowIncomingCallUi() {
129
124
  super.onShowIncomingCallUi()
130
- Log.d(TAG, "onShowIncomingCallUi for callId: $callId. Attempting to bring app to foreground.")
131
- CallEngine.bringAppToForeground(context)
125
+ Log.d(TAG, "onShowIncomingCallUi for callId: $callId. Showing CallActivity, not bringing MainActivity to foreground yet.")
126
+ // Don't bring MainActivity to foreground here - only show CallActivity
127
+ // MainActivity will be brought to foreground when the call is answered
132
128
  }
133
129
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qusaieilouti99/call-manager",
3
- "version": "0.1.43",
3
+ "version": "0.1.44",
4
4
  "description": "Call manager",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",