Фикс 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 ->
|
keysToClear.forEach { key ->
|
||||||
cancelNotificationForChat(applicationContext, 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
|
handledByData = true
|
||||||
}
|
}
|
||||||
@@ -588,6 +593,118 @@ class RosettaFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
return candidates
|
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 {
|
private fun isAvatarInNotificationsEnabled(): Boolean {
|
||||||
return runCatching {
|
return runCatching {
|
||||||
runBlocking(Dispatchers.IO) {
|
runBlocking(Dispatchers.IO) {
|
||||||
|
|||||||
Reference in New Issue
Block a user