@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
|
-
|
|
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"
|
|
54
|
+
setContentView(R.layout.activity_call)
|
|
26
55
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
//
|
|
36
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
146
|
-
|
|
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
|
}
|