Фикс FCM: убран неиспользуемый импорт CallUiState
All checks were successful
Android Kernel Build / build (push) Successful in 19m8s

This commit is contained in:
2026-04-05 16:46:57 +05:00
parent b8c5529b29
commit 152106eda1

View File

@@ -206,7 +206,12 @@ class RosettaFirebaseMessagingService : FirebaseMessagingService() {
keysToClear.forEach { key ->
cancelNotificationForChat(applicationContext, key)
}
Log.d(TAG, "READ push cleared notifications for keys=$keysToClear")
val titleHints = collectReadTitleHints(data, keysToClear)
cancelMatchingActiveNotifications(keysToClear, titleHints)
Log.d(
TAG,
"READ push cleared notifications for keys=$keysToClear titles=$titleHints"
)
}
handledByData = true
}
@@ -588,6 +593,118 @@ class RosettaFirebaseMessagingService : FirebaseMessagingService() {
return candidates
}
private fun collectReadTitleHints(
data: Map<String, String>,
dialogKeys: Set<String>
): Set<String> {
val hints = linkedSetOf<String>()
fun add(raw: String?) {
val value = raw?.trim().orEmpty()
if (value.isNotBlank()) hints.add(value)
}
add(firstNonBlank(data, "title", "sender_name", "sender_title", "from_title", "name"))
dialogKeys.forEach { key ->
add(resolveNameForKey(key))
}
return hints
}
/**
* Fallback for system-shown notifications with unknown IDs (FCM notification payload path).
* Matches active notifications by:
* 1) deterministic dialog hash id
* 2) dialog key/group key in notification extras/text
* 3) known dialog title hints
*/
private fun cancelMatchingActiveNotifications(
dialogKeys: Set<String>,
titleHints: Set<String>
) {
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager ?: return
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return
val normalizedDialogKeys =
dialogKeys
.flatMap { key ->
buildDialogKeyVariants(key).toList() + key.trim()
}
.map { it.trim() }
.filter { it.isNotEmpty() }
.toSet()
val normalizedHints = titleHints.map { it.trim() }.filter { it.isNotEmpty() }.toSet()
if (normalizedDialogKeys.isEmpty() && normalizedHints.isEmpty()) return
runCatching {
manager.activeNotifications.forEach { sbn ->
val notification = sbn.notification ?: return@forEach
if (notification.channelId == "rosetta_calls") return@forEach
val title =
notification.extras
?.getCharSequence(android.app.Notification.EXTRA_TITLE)
?.toString()
?.trim()
.orEmpty()
val text =
notification.extras
?.getCharSequence(android.app.Notification.EXTRA_TEXT)
?.toString()
?.trim()
.orEmpty()
val bigText =
notification.extras
?.getCharSequence(android.app.Notification.EXTRA_BIG_TEXT)
?.toString()
?.trim()
.orEmpty()
val bag = mutableSetOf<String>()
if (title.isNotEmpty()) bag.add(title)
if (text.isNotEmpty()) bag.add(text)
if (bigText.isNotEmpty()) bag.add(bigText)
notification.extras?.keySet()?.forEach { extraKey ->
bag.add(extraKey)
val value = notification.extras?.get(extraKey)
when (value) {
is CharSequence -> bag.add(value.toString())
is String -> bag.add(value)
is Array<*> -> value.filterIsInstance<CharSequence>().forEach { bag.add(it.toString()) }
}
}
val bagLower = bag.map { it.lowercase(Locale.ROOT) }
val matchesDialogKey =
normalizedDialogKeys.any { key ->
val lowerKey = key.lowercase(Locale.ROOT)
bagLower.any { it.contains(lowerKey) }
}
val matchesHint =
normalizedHints.any { hint ->
title.equals(hint, ignoreCase = true) ||
text.contains(hint, ignoreCase = true) ||
bigText.contains(hint, ignoreCase = true)
}
val matchesDeterministicId =
normalizedDialogKeys.any { key ->
getNotificationIdForChat(key) == sbn.id
}
if (matchesDeterministicId || matchesDialogKey || matchesHint) {
manager.cancel(sbn.tag, sbn.id)
Log.d(
TAG,
"READ push fallback cancel id=${sbn.id} tag=${sbn.tag} " +
"channel=${notification.channelId} title='$title' " +
"matchId=$matchesDeterministicId matchKey=$matchesDialogKey matchHint=$matchesHint"
)
}
}
}.onFailure { error ->
Log.w(TAG, "cancelMatchingActiveNotifications failed: ${error.message}")
}
}
private fun isAvatarInNotificationsEnabled(): Boolean {
return runCatching {
runBlocking(Dispatchers.IO) {