Фикс FCM: убран неиспользуемый импорт CallUiState
All checks were successful
Android Kernel Build / build (push) Successful in 19m8s
All checks were successful
Android Kernel Build / build (push) Successful in 19m8s
This commit is contained in:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user