@qusaieilouti99/call-manager 0.1.77 → 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,168 +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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
24
|
-
private var callId: String = ""
|
|
25
|
-
private var callType: String = "Audio"
|
|
26
|
-
|
|
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.stopRingtone()
|
|
32
|
-
CallEngine.cancelIncomingCallUI()
|
|
33
|
-
CallEngine.endCall(callId)
|
|
34
|
-
finishCallActivity()
|
|
35
|
-
}
|
|
54
|
+
setContentView(R.layout.activity_call)
|
|
36
55
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (receivedCallId == callId || receivedCallId.isNullOrEmpty()) {
|
|
43
|
-
Log.d(TAG, "Received close broadcast for $callId")
|
|
44
|
-
finishReason = FinishReason.EXTERNAL_END
|
|
45
|
-
|
|
46
|
-
// Ensure we're on main thread and activity isn't finishing
|
|
47
|
-
runOnUiThread {
|
|
48
|
-
if (!isFinishing) {
|
|
49
|
-
finishCallActivity()
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
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")
|
|
55
60
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
setShowWhenLocked(true)
|
|
63
|
-
setTurnScreenOn(true)
|
|
64
|
-
} else {
|
|
65
|
-
// Legacy approach for older versions
|
|
66
|
-
window.addFlags(
|
|
67
|
-
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
|
|
68
|
-
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
|
|
69
|
-
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
|
|
70
|
-
)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
setContentView(R.layout.activity_call)
|
|
74
|
-
|
|
75
|
-
callId = intent.getStringExtra("callId") ?: ""
|
|
76
|
-
callType = intent.getStringExtra("callType") ?: "Audio"
|
|
77
|
-
Log.d(TAG, "CallActivity received callId: $callId, callType: $callType")
|
|
78
|
-
|
|
79
|
-
// FIXED: Don't immediately cancel ringtone and notification - let them play
|
|
80
|
-
// CallEngine.cancelIncomingCallUI() // REMOVED
|
|
81
|
-
|
|
82
|
-
val callerName = intent.getStringExtra("callerName") ?: "Unknown"
|
|
83
|
-
val nameView = findViewById<TextView>(R.id.caller_name)
|
|
84
|
-
val answerBtn = findViewById<Button>(R.id.answer_btn)
|
|
85
|
-
val declineBtn = findViewById<Button>(R.id.decline_btn)
|
|
86
|
-
|
|
87
|
-
nameView.text = callerName
|
|
88
|
-
|
|
89
|
-
answerBtn.setOnClickListener {
|
|
90
|
-
Log.d(TAG, "CallActivity: Answer button clicked for callId: $callId")
|
|
91
|
-
finishReason = FinishReason.ANSWER
|
|
92
|
-
// Stop ringtone and notification when user answers
|
|
93
|
-
CallEngine.stopRingtone()
|
|
94
|
-
CallEngine.cancelIncomingCallUI()
|
|
95
|
-
CallEngine.answerCall(callId)
|
|
96
|
-
finishCallActivity()
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
declineBtn.setOnClickListener {
|
|
100
|
-
Log.d(TAG, "CallActivity: Decline button clicked for callId: $callId")
|
|
101
|
-
finishReason = FinishReason.DECLINE
|
|
102
|
-
// Stop ringtone and notification when user declines
|
|
103
|
-
CallEngine.stopRingtone()
|
|
104
|
-
CallEngine.cancelIncomingCallUI()
|
|
105
|
-
CallEngine.endCall(callId)
|
|
106
|
-
finishCallActivity()
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Enhanced broadcast receiver registration
|
|
110
|
-
val filter = IntentFilter("com.qusaieilouti99.callmanager.CLOSE_CALL_ACTIVITY")
|
|
111
|
-
try {
|
|
112
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
113
|
-
registerReceiver(closeReceiver, filter, Context.RECEIVER_NOT_EXPORTED)
|
|
114
|
-
} else {
|
|
115
|
-
registerReceiver(closeReceiver, filter)
|
|
116
|
-
}
|
|
117
|
-
Log.d(TAG, "Broadcast receiver registered successfully for callId: $callId")
|
|
118
|
-
} catch (e: Exception) {
|
|
119
|
-
Log.e(TAG, "Failed to register broadcast receiver: ${e.message}", e)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Set timeout for incoming call
|
|
123
|
-
timeoutHandler.postDelayed(timeoutRunnable, 60_000)
|
|
124
|
-
Log.d(TAG, "CallActivity onCreate - END")
|
|
125
|
-
}
|
|
61
|
+
// Register for call‐end callbacks BEFORE timeout or user can dismiss
|
|
62
|
+
CallEngine.registerCallEndListener(this)
|
|
63
|
+
|
|
64
|
+
// Bind UI
|
|
65
|
+
val callerName = intent.getStringExtra("callerName") ?: "Unknown"
|
|
66
|
+
findViewById<TextView>(R.id.caller_name).text = callerName
|
|
126
67
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
// Unregister broadcast receiver with better error handling
|
|
135
|
-
try {
|
|
136
|
-
unregisterReceiver(closeReceiver)
|
|
137
|
-
Log.d(TAG, "Broadcast receiver unregistered for callId: $callId")
|
|
138
|
-
} catch (e: IllegalArgumentException) {
|
|
139
|
-
Log.w(TAG, "Receiver was not registered: ${e.message}")
|
|
140
|
-
} catch (e: Exception) {
|
|
141
|
-
Log.e(TAG, "Error unregistering receiver: ${e.message}", e)
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Clean up ringtone and notification if call wasn't answered
|
|
145
|
-
if (finishReason != FinishReason.ANSWER) {
|
|
146
|
-
CallEngine.stopRingtone()
|
|
147
|
-
CallEngine.cancelIncomingCallUI()
|
|
148
|
-
}
|
|
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()
|
|
149
75
|
}
|
|
150
76
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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()
|
|
158
84
|
}
|
|
159
85
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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()
|
|
172
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() }
|
|
126
|
+
}
|
|
127
|
+
}
|
|
173
128
|
|
|
174
|
-
|
|
175
|
-
|
|
129
|
+
private fun finishCallActivity() {
|
|
130
|
+
if (isFinishing) {
|
|
131
|
+
Log.d(TAG, "Already finishing, skip.")
|
|
132
|
+
return
|
|
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()
|
|
176
139
|
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
companion object {
|
|
143
|
+
private const val TAG = "CallActivity"
|
|
144
|
+
}
|
|
177
145
|
}
|