Skip to content

Commit 3e787f3

Browse files
ly85206559steipete
andauthored
fix(android): preserve UTF-16 boundaries in notification text (#102442)
* fix(android): keep notification text UTF-16 safe * test(android): cover UTF-16 notification boundaries --------- Co-authored-by: Peter Steinberger <[email protected]> Co-authored-by: Peter Steinberger <[email protected]>
1 parent 363cf04 commit 3e787f3

2 files changed

Lines changed: 24 additions & 1 deletion

File tree

apps/android/app/src/main/java/ai/openclaw/app/node/DeviceNotificationListenerService.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,18 @@ private const val NOTIFICATIONS_CHANGED_EVENT = "notifications.changed"
2727
internal fun sanitizeNotificationText(value: CharSequence?): String? {
2828
val normalized = value?.toString()?.trim().orEmpty()
2929
// Notification extras can include long previews; cap before sending over node events.
30-
return normalized.take(MAX_NOTIFICATION_TEXT_CHARS).ifEmpty { null }
30+
return normalized.takeUtf16Safe(MAX_NOTIFICATION_TEXT_CHARS).ifEmpty { null }
31+
}
32+
33+
private fun String.takeUtf16Safe(maxChars: Int): String {
34+
if (length <= maxChars) return this
35+
val end =
36+
if (maxChars > 0 && Character.isHighSurrogate(this[maxChars - 1])) {
37+
maxChars - 1
38+
} else {
39+
maxChars
40+
}
41+
return take(end)
3142
}
3243

3344
/**

apps/android/app/src/test/java/ai/openclaw/app/node/NotificationsHandlerTest.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,18 @@ class NotificationsHandlerTest {
265265
assertTrue((sanitized ?: "").all { it == 'x' })
266266
}
267267

268+
@Test
269+
fun sanitizeNotificationTextPreservesUtf16BoundariesAtLimit() {
270+
val splitPairPrefix = "a".repeat(511)
271+
assertEquals(splitPairPrefix, sanitizeNotificationText("$splitPairPrefix🚀 trailing text"))
272+
273+
val completePairPrefix = "a".repeat(510)
274+
assertEquals(
275+
"$completePairPrefix🚀",
276+
sanitizeNotificationText("$completePairPrefix🚀 trailing text"),
277+
)
278+
}
279+
268280
@Test
269281
fun notificationsActionClearablePolicy_onlyRequiresClearableForDismiss() {
270282
assertTrue(actionRequiresClearableNotification(NotificationActionKind.Dismiss))

0 commit comments

Comments
 (0)