I have textfield that I am setting text string and...
# android
s
I have textfield that I am setting text string and observing strange issue If the string is "🙏" which is codepoints 128591 1f64f I see the first image, But if the string is "🙏🙏" which is basically 2 code points with values 128591 128591, I see the second image Is there something special I need to do in order for the first emoji to get rendered correctly in a textView? The emoji in question is - https://www.unicodepedia.com/unicode/emoticons/1f64f/person-with-folded-hands/
s
How do you set the text can you share the exact string you set on textview?
s
I am using textView.setText method, also as additional data point I am using androidx.appcompatappcompat1.4.1 , I thought I don't need to any specific EmojiCompat initialization etc. per this web page - https://developer.android.com/develop/ui/views/text-and-emoji/emoji2
s
What is the exact string that you set on textview as string?
s
textView.setText(":pray::pray:") or textView.setText(":pray:")
FWIW I just updated my appCompt to 1.5.0 and and compileSdk to 32, and I see the same results on Android emulator with version 12. As well as Pixel 4a physical device running Android 13.
Here is the code I am using to print my debug out
Copy code
private fun printMe(
    spannableText: SpannableStringBuilder,
) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        val byteArray16 = spannableText.toString().toByteArray(Charsets.UTF_16)
        val byteArray8 = spannableText.toString().toByteArray(Charsets.UTF_8)
        val cpArray = spannableText.toString().codePoints().toArray()
        Logger.debug("EMOJI", spannableText.toString())
        Logger.debug("EMOJI",
            "Spannable length ${spannableText.length} String len ${spannableText.toString().length} Codepoint count " +
                spannableText.toString().codePointCount(0, spannableText.toString().length),
        )
        var str8 = ""
        var str16 = ""
        var strCp = ""

        byteArray8.forEachIndexed { index: Int, byte: Byte ->
            str8 += "$index 0x" + byte.toHexString() + " "
        }
        byteArray16.forEachIndexed { index: Int, byte: Byte ->
            str16 += "$index 0x" + byte.toHexString() + " "
        }
        cpArray.forEachIndexed { index, cp ->
            strCp += "$index 0x" + cp.toHexString() + " "
        }
        Logger.debug("EMOJI", "UTF_8 $str8")
        Logger.debug("EMOJI", "UTF_16 $str8")
        Logger.debug("EMOJI", "CodePoint $strCp")
    }
}
And this is the output I see D EMOJI : 🙏🙏 D EMOJI : Spannable length 4 String len 4 Codepoint count 2 D EMOJI : UTF_8 0 0xf0 1 0x9f 2 0x99 3 0x8f 4 0xf0 5 0x9f 6 0x99 7 0x8f D EMOJI : UTF_16 0 0xf0 1 0x9f 2 0x99 3 0x8f 4 0xf0 5 0x9f 6 0x99 7 0x8f D EMOJI : CodePoint 0 0x1f64f 1 0x1f64f
Above issue was because I was setting wrong length on spannable string that had emoji. I distilled the code down to following
Copy code
val spannableText = SpannableString("x\uD83D\uDE4F")
val urlSpan = URLSpan("<https://www.google.com/>")
spannableText.setSpan(
    urlSpan,
    1,
    2,
    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
That produces output that looks like this: In above example if I set start and end position of the span "correctly" over the entire emoji things look correct.
Copy code
val spannableText = SpannableString("x\uD83D\uDE4F")
val urlSpan = URLSpan("<https://www.google.com/>")
spannableText.setSpan(
    urlSpan,
    1,
    3,
    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
I have code that builds complex spannable, so I got computation of span length wrong when there is codepoint/emoji in the string. I "distilled" my issue above. Posting an update here, in case someone runs into this in the future. I had posted query here too -- https://stackoverflow.com/questions/73595754/android-issue-with-rendering-emoji/73604405#73604405
👍 1
a
This is what would be called a “Unicode Grapheme Cluster”
👍 1