feat(video_calls): fixed call ended push handling

This commit is contained in:
misha
2026-06-30 18:48:45 +03:00
parent c8ad600d97
commit 9ce7b035ff
5 changed files with 138 additions and 13 deletions

View File

@@ -25,8 +25,10 @@ class MainActivity: FlutterActivity() {
private val channelName = "com.eatvioapp/hms_push"
private val videoCallPipChannelName = "com.eatvioapp/video_call_pip"
private val videoCallPushChannelName = "com.eatvioapp/video_call_push"
private var methodChannel: MethodChannel? = null
private var videoCallPipChannel: MethodChannel? = null
private var videoCallPushChannel: MethodChannel? = null
private var videoCallPipEnabled: Boolean = false
override fun onResume() {
@@ -44,6 +46,20 @@ class MainActivity: FlutterActivity() {
methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, channelName)
videoCallPipChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, videoCallPipChannelName)
videoCallPushChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, videoCallPushChannelName)
videoCallPushChannel?.setMethodCallHandler { call, result ->
when (call.method) {
"dismissIncomingCalls" -> {
try {
VideoCallPushBridge.dismissAllIncomingCalls(applicationContext)
result.success(null)
} catch (e: Exception) {
result.error("DISMISS_INCOMING_CALLS_FAILED", e.message, null)
}
}
else -> result.notImplemented()
}
}
videoCallPipChannel?.setMethodCallHandler { call, result ->
when (call.method) {
"setPipEnabled" -> {

View File

@@ -2,12 +2,17 @@ package com.eatvioapp.app
import android.content.Context
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.hiennv.flutter_callkit_incoming.CallkitConstants
import com.hiennv.flutter_callkit_incoming.CallkitIncomingBroadcastReceiver
import com.hiennv.flutter_callkit_incoming.CallkitNotificationManager
import com.hiennv.flutter_callkit_incoming.CallkitNotificationService
import com.hiennv.flutter_callkit_incoming.CallkitSoundPlayerManager
import com.hiennv.flutter_callkit_incoming.Data
import com.hiennv.flutter_callkit_incoming.FlutterCallkitIncomingPlugin
import com.hiennv.flutter_callkit_incoming.addCall
import com.hiennv.flutter_callkit_incoming.getDataActiveCalls
import com.hiennv.flutter_callkit_incoming.removeAllCalls
@@ -16,6 +21,10 @@ import java.util.HashMap
object VideoCallPushBridge {
private const val TAG = "VideoCallPushBridge"
private const val ANDROID_ACCENT_COLOR = "#2787F5"
private const val MISSED_CALL_CLEANUP_DELAY_MS = 250L
private var activeSoundManager: CallkitSoundPlayerManager? = null
private var activeNotificationManager: CallkitNotificationManager? = null
fun isIncomingVideoCall(data: Map<String, String>): Boolean {
val rawType = data["type"]
@@ -90,6 +99,8 @@ object VideoCallPushBridge {
val soundManager = CallkitSoundPlayerManager(appContext)
val notificationManager = CallkitNotificationManager(appContext, soundManager)
activeSoundManager = soundManager
activeNotificationManager = notificationManager
notificationManager.createNotificationChanel(callData)
notificationManager.showIncomingNotification(callData)
@@ -105,28 +116,108 @@ object VideoCallPushBridge {
val calls = getDataActiveCalls(appContext)
Log.i(TAG, "dismissAllIncomingCalls: active calls=${calls.size}")
val soundManager = CallkitSoundPlayerManager(appContext)
val notificationManager = CallkitNotificationManager(appContext, soundManager)
stopIncomingRingtone(appContext)
for (call in calls) {
val bundle = call.toBundle()
val notificationManager = resolveNotificationManager(appContext)
val bundles = calls.map { it.toBundle() }
for (bundle in bundles) {
try {
notificationManager.clearIncomingNotification(bundle, isAccepted = false)
appContext.sendBroadcast(
CallkitIncomingBroadcastReceiver.getIntentEnded(appContext, bundle),
)
dismissIncomingCallNotification(appContext, notificationManager, bundle)
} catch (error: Exception) {
Log.w(TAG, "dismissAllIncomingCalls: failed for call ${call.id}", error)
Log.w(
TAG,
"dismissAllIncomingCalls: failed for call ${bundle.getString(CallkitConstants.EXTRA_CALLKIT_ID)}",
error,
)
}
}
try {
CallkitNotificationService.stopService(appContext)
} catch (error: Exception) {
Log.w(TAG, "dismissAllIncomingCalls: failed to stop callkit service", error)
}
try {
removeAllCalls(appContext)
} catch (error: Exception) {
Log.w(TAG, "dismissAllIncomingCalls: failed to remove persisted calls", error)
}
soundManager.stop()
stopIncomingRingtone(appContext)
scheduleMissedCallCleanup(notificationManager, bundles)
activeSoundManager = null
activeNotificationManager = null
}
private fun resolveNotificationManager(context: Context): CallkitNotificationManager {
activeNotificationManager?.let { return it }
FlutterCallkitIncomingPlugin.getInstance()
?.getCallkitNotificationManager()
?.let { return it }
val soundManager = CallkitSoundPlayerManager(context)
return CallkitNotificationManager(context, soundManager)
}
private fun stopIncomingRingtone(context: Context) {
activeSoundManager?.stop()
FlutterCallkitIncomingPlugin.getInstance()
?.getCallkitSoundPlayerManager()
?.stop()
}
/**
* Replaces the incoming notification before cancel so Android does not fire the
* timeout delete intent (which would show a missed-call notification).
*/
private fun dismissIncomingCallNotification(
context: Context,
notificationManager: CallkitNotificationManager,
bundle: Bundle,
) {
val notificationId = incomingNotificationId(bundle)
val silentNotification = NotificationCompat.Builder(
context,
CallkitNotificationManager.NOTIFICATION_CHANNEL_ID_INCOMING,
)
.setSmallIcon(context.applicationInfo.icon)
.setContentTitle("")
.setSilent(true)
.setOngoing(false)
.setPriority(NotificationCompat.PRIORITY_MIN)
.build()
val notificationManagerCompat = NotificationManagerCompat.from(context)
notificationManagerCompat.notify(notificationId, silentNotification)
notificationManagerCompat.cancel(notificationId)
bundle.putBoolean(CallkitConstants.EXTRA_CALLKIT_MISSED_CALL_SHOW, false)
notificationManager.clearIncomingNotification(bundle, isAccepted = true)
notificationManager.clearMissCallNotification(bundle)
}
private fun scheduleMissedCallCleanup(
notificationManager: CallkitNotificationManager,
bundles: List<Bundle>,
) {
if (bundles.isEmpty()) return
Handler(Looper.getMainLooper()).postDelayed({
for (bundle in bundles) {
try {
notificationManager.clearMissCallNotification(bundle)
} catch (error: Exception) {
Log.w(TAG, "dismissAllIncomingCalls: delayed missed-call cleanup failed", error)
}
}
}, MISSED_CALL_CLEANUP_DELAY_MS)
}
private fun incomingNotificationId(bundle: Bundle): Int {
return bundle.getString(CallkitConstants.EXTRA_CALLKIT_ID, "callkit_incoming").hashCode()
}
private fun buildCallDataBundle(data: Map<String, String>): Bundle? {

File diff suppressed because one or more lines are too long