@qusaieilouti99/call-manager 0.1.76 → 0.1.78

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,7 +1,7 @@
1
+ // File: CallActivity.kt
1
2
  package com.margelo.nitro.qusaieilouti99.callmanager
2
3
 
3
4
  import android.app.Activity
4
- import android.content.Intent
5
5
  import android.os.Build
6
6
  import android.os.Bundle
7
7
  import android.os.Handler
@@ -10,139 +10,136 @@ import android.util.Log
10
10
  import android.view.WindowManager
11
11
  import android.widget.Button
12
12
  import android.widget.TextView
13
- import android.content.BroadcastReceiver
14
- import android.content.Context
15
- import android.content.IntentFilter
16
13
 
17
- class CallActivity : Activity() {
18
-
19
- private enum class FinishReason {
20
- ANSWER, DECLINE, TIMEOUT, MANUAL_DISMISS, EXTERNAL_END
14
+ /**
15
+ * Full‐screen incoming‐call UI. Implements CallEndListener
16
+ * so it always auto‐finishes when the engine ends the call.
17
+ */
18
+ class CallActivity : Activity(), CallEngine.CallEndListener {
19
+
20
+ private enum class FinishReason {
21
+ ANSWER, DECLINE, TIMEOUT, MANUAL_DISMISS, EXTERNAL_END
22
+ }
23
+
24
+ private var finishReason: FinishReason? = null
25
+ private var callId: String = ""
26
+ private var callType: String = "Audio"
27
+
28
+ private val timeoutHandler = Handler(Looper.getMainLooper())
29
+ private val timeoutRunnable = Runnable {
30
+ Log.d(TAG, "CallActivity timeout triggered for callId: $callId")
31
+ finishReason = FinishReason.TIMEOUT
32
+ CallEngine.stopRingtone()
33
+ CallEngine.cancelIncomingCallUI()
34
+ CallEngine.endCall(callId)
35
+ finishCallActivity()
36
+ }
37
+
38
+ override fun onCreate(savedInstanceState: Bundle?) {
39
+ super.onCreate(savedInstanceState)
40
+ Log.d(TAG, "CallActivity onCreate")
41
+
42
+ // Lock‐screen bypass
43
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
44
+ setShowWhenLocked(true)
45
+ setTurnScreenOn(true)
46
+ } else {
47
+ window.addFlags(
48
+ WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
49
+ WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
50
+ WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
51
+ )
21
52
  }
22
53
 
23
- private var finishReason: FinishReason? = null
24
- private var callId: String = ""
25
- private var callType: String = "Audio"
54
+ setContentView(R.layout.activity_call)
26
55
 
27
- private val timeoutHandler = Handler(Looper.getMainLooper())
28
- private val timeoutRunnable = Runnable {
29
- Log.d(TAG, "CallActivity timeout triggered for callId: $callId")
30
- finishReason = FinishReason.TIMEOUT
31
- CallEngine.endCall(callId)
32
- finishCallActivity()
33
- }
56
+ // Read incoming‐call params
57
+ callId = intent.getStringExtra("callId") ?: ""
58
+ callType = intent.getStringExtra("callType") ?: "Audio"
59
+ Log.d(TAG, "CallActivity received callId: $callId, callType: $callType")
34
60
 
35
- // NEW: Broadcast receiver to listen for close events
36
- private val closeReceiver = object : BroadcastReceiver() {
37
- override fun onReceive(context: Context?, intent: Intent?) {
38
- val receivedCallId = intent?.getStringExtra("callId")
39
- if (receivedCallId == callId) {
40
- Log.d(TAG, "Received close broadcast for $callId")
41
- finishReason = FinishReason.EXTERNAL_END
42
- finishCallActivity()
43
- }
44
- }
45
- }
61
+ // Register for call‐end callbacks BEFORE timeout or user can dismiss
62
+ CallEngine.registerCallEndListener(this)
46
63
 
47
- override fun onCreate(savedInstanceState: Bundle?) {
48
- super.onCreate(savedInstanceState)
49
- Log.d(TAG, "CallActivity onCreate")
50
-
51
- // Modern way to handle lock screen bypass (API 27+)
52
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
53
- setShowWhenLocked(true)
54
- setTurnScreenOn(true)
55
- } else {
56
- // Legacy approach for older versions
57
- window.addFlags(
58
- WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
59
- WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
60
- WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
61
- )
62
- }
63
-
64
- setContentView(R.layout.activity_call)
65
-
66
- callId = intent.getStringExtra("callId") ?: ""
67
- callType = intent.getStringExtra("callType") ?: "Audio"
68
- Log.d(TAG, "CallActivity received callId: $callId, callType: $callType")
69
-
70
- // FIXED: Immediate cleanup of notifications when CallActivity is shown
71
- CallEngine.cancelIncomingCallUI()
72
-
73
- val callerName = intent.getStringExtra("callerName") ?: "Unknown"
74
- val nameView = findViewById<TextView>(R.id.caller_name)
75
- val answerBtn = findViewById<Button>(R.id.answer_btn)
76
- val declineBtn = findViewById<Button>(R.id.decline_btn)
77
-
78
- nameView.text = callerName
79
-
80
- answerBtn.setOnClickListener {
81
- Log.d(TAG, "CallActivity: Answer button clicked for callId: $callId")
82
- finishReason = FinishReason.ANSWER
83
- CallEngine.answerCall(callId)
84
- finishCallActivity()
85
- }
86
-
87
- declineBtn.setOnClickListener {
88
- Log.d(TAG, "CallActivity: Decline button clicked for callId: $callId")
89
- finishReason = FinishReason.DECLINE
90
- CallEngine.endCall(callId)
91
- finishCallActivity()
92
- }
93
-
94
- // NEW: Register broadcast receiver
95
- val filter = IntentFilter("com.qusaieilouti99.callmanager.CLOSE_CALL_ACTIVITY")
96
- try {
97
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
98
- registerReceiver(closeReceiver, filter, Context.RECEIVER_NOT_EXPORTED)
99
- Log.d(TAG, "Broadcast receiver registered successfully (API 33+)")
100
- } else {
101
- registerReceiver(closeReceiver, filter)
102
- Log.d(TAG, "Broadcast receiver registered successfully (API < 33)")
103
- }
104
- } catch (e: Exception) {
105
- Log.e(TAG, "Failed to register broadcast receiver: ${e.message}", e)
106
- }
107
-
108
- timeoutHandler.postDelayed(timeoutRunnable, 60_000)
109
- Log.d(TAG, "CallActivity onCreate - END")
110
- }
64
+ // Bind UI
65
+ val callerName = intent.getStringExtra("callerName") ?: "Unknown"
66
+ findViewById<TextView>(R.id.caller_name).text = callerName
111
67
 
112
- override fun onDestroy() {
113
- super.onDestroy()
114
- Log.d(TAG, "CallActivity onDestroy for callId: $callId. Reason: $finishReason")
115
- timeoutHandler.removeCallbacks(timeoutRunnable)
116
-
117
- // NEW: Unregister broadcast receiver
118
- try {
119
- unregisterReceiver(closeReceiver)
120
- } catch (e: Exception) {
121
- Log.w(TAG, "Receiver already unregistered: ${e.message}")
122
- }
123
-
124
- // FIXED: Ensure cleanup happens regardless of how activity ends
125
- CallEngine.stopRingtone()
126
- CallEngine.cancelIncomingCallUI()
68
+ findViewById<Button>(R.id.answer_btn).setOnClickListener {
69
+ Log.d(TAG, "Answer clicked for callId: $callId")
70
+ finishReason = FinishReason.ANSWER
71
+ CallEngine.stopRingtone()
72
+ CallEngine.cancelIncomingCallUI()
73
+ CallEngine.answerCall(callId)
74
+ finishCallActivity()
127
75
  }
128
76
 
129
- override fun onBackPressed() {
130
- Log.d(TAG, "CallActivity onBackPressed for callId: $callId. Treating as decline/dismiss.")
131
- finishReason = FinishReason.MANUAL_DISMISS
132
- CallEngine.endCall(callId)
133
- finishCallActivity()
77
+ findViewById<Button>(R.id.decline_btn).setOnClickListener {
78
+ Log.d(TAG, "Decline clicked for callId: $callId")
79
+ finishReason = FinishReason.DECLINE
80
+ CallEngine.stopRingtone()
81
+ CallEngine.cancelIncomingCallUI()
82
+ CallEngine.endCall(callId)
83
+ finishCallActivity()
134
84
  }
135
85
 
136
- private fun finishCallActivity() {
137
- Log.d(TAG, "Finishing CallActivity.")
138
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
139
- finishAndRemoveTask()
140
- } else {
141
- finish()
142
- }
86
+ // Start auto‐timeout
87
+ timeoutHandler.postDelayed(timeoutRunnable, 60_000)
88
+ Log.d(TAG, "CallActivity setup complete")
89
+ }
90
+
91
+ override fun onDestroy() {
92
+ super.onDestroy()
93
+ Log.d(TAG, "CallActivity onDestroy for callId: $callId. Reason: $finishReason")
94
+
95
+ // Unregister listener
96
+ CallEngine.unregisterCallEndListener(this)
97
+
98
+ // Cancel timeout
99
+ timeoutHandler.removeCallbacks(timeoutRunnable)
100
+
101
+ // If user never answered, clean up ringtone/UI
102
+ if (finishReason != FinishReason.ANSWER) {
103
+ CallEngine.stopRingtone()
104
+ CallEngine.cancelIncomingCallUI()
105
+ }
106
+ }
107
+
108
+ override fun onBackPressed() {
109
+ Log.d(TAG, "onBackPressed for callId: $callId → treat as decline")
110
+ finishReason = FinishReason.MANUAL_DISMISS
111
+ CallEngine.stopRingtone()
112
+ CallEngine.cancelIncomingCallUI()
113
+ CallEngine.endCall(callId)
114
+ finishCallActivity()
115
+ }
116
+
117
+ /**
118
+ * Called by CallEngine whenever ANY call ends.
119
+ * We only care about our own callId.
120
+ */
121
+ override fun onCallEnded(endedCallId: String) {
122
+ if (endedCallId == callId && !isFinishing) {
123
+ Log.d(TAG, "CallActivity onCallEnded callback for callId: $callId")
124
+ finishReason = FinishReason.EXTERNAL_END
125
+ runOnUiThread { finishCallActivity() }
143
126
  }
127
+ }
144
128
 
145
- companion object {
146
- private const val TAG = "CallActivity"
129
+ private fun finishCallActivity() {
130
+ if (isFinishing) {
131
+ Log.d(TAG, "Already finishing, skip.")
132
+ return
147
133
  }
134
+ Log.d(TAG, "Finishing CallActivity for callId: $callId")
135
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
136
+ finishAndRemoveTask()
137
+ } else {
138
+ finish()
139
+ }
140
+ }
141
+
142
+ companion object {
143
+ private const val TAG = "CallActivity"
144
+ }
148
145
  }