Android Emoji App Compat Text View not rendering some emojis such as 👁
Asked Answered
T

1

7

I'm trying to use the Emoji App Compat Text View but I don't understand what I'm doing wrong on my implementation.

I'm trying to render these three emojis 👣👁👀, it works fine on Android Q, but it is not working on Android Lollipop, take a look at the screenshots:

Screenshot on Android Q Screenshot on Android Lollipop
Screenshot on Android Q Screenshot on Android Lollipop

As far as I understood the idea of using the Emoji App Compat Text View is to get the emoji set working fine from android API 21 and later, so please take a look at my implementation, is there anything missing, wrong or maybe Emoji App Compat Text View does not work as I thought?

You can get the complete code here at github or read the main parts below:

Application's onCreate, set up the EmojiCompat, I'm not using the bundled version:

EmojiCompat.init(
    FontRequestEmojiCompatConfig(
        this,
        FontRequest(
            "com.google.android.gms.fonts",
            "com.google.android.gms",
            "Noto Color Emoji Compat",
            R.array.com_google_android_gms_fonts_certs
        )
    ).setReplaceAll(true)
    // I did remove the callback for brevity, but I got the `onInitialized` called.
)

Activity, just set the layout, get the View and set the text:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
…
    <androidx.emoji.widget.EmojiAppCompatTextView
        android:id="@+id/text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="60sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
…
</androidx.constraintlayout.widget.ConstraintLayout>
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        findViewById<EmojiAppCompatTextView>(R.id.text_view).text = getString(R.string.three_emojis)
    }
}

Strings

<string name="three_emojis">👣👁👀</string>

gradle

plugins {
    id "com.android.application"
    id "kotlin-android"
}

android {
    compileSdkVersion 29
    buildToolsVersion "30.0.2"
…
    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 29
…
    }
…
}

dependencies {
    implementation "androidx.emoji:emoji-appcompat:1.1.0"
    implementation "androidx.emoji:emoji:1.1.0"
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation "androidx.appcompat:appcompat:1.2.0"
    implementation "androidx.constraintlayout:constraintlayout:2.0.4"
    implementation "androidx.core:core-ktx:1.3.2"
    implementation "com.google.android.material:material:1.2.1"
}
Tallyman answered 19/12, 2020 at 17:20 Comment(4)
This is very strange behavior. I have tried same emoji from emojipedia.org/eye and it works. Even looks the same to your emoji. Also did comparation with r12a.github.io/app-conversion and both 'eye' emojis have same data. imgur.com/a/I9B7pSAMouthy
@HarisDautović I have no words and no idea what is happening, but I did reproduce your example and I got the same result. I did run kotlinc-jvm and "👁"=="👁", left is the original and right came from emojipedia, the result was res1: kotlin.Boolean = true.Tallyman
Here is some additional debugging data: imgur.com/a/fbFqvsa Data value contain only eye emoji. Case 1: Doesn't work -> Decoded emoji has 2 characters. Case 2: It works -> Decoded emoji has 3 characters. Third character is empty.Mouthy
@HarisDautović I think you hit the nail on the head, reading about this 65039 character, it is the Variation selector-16 and according to Wikipedia VS15 and VS16 are reserved to request that a character should be displayed as text or as an emoji respectively. So to test it, I did run .text = String(charArrayOf('\uD83D', '\uDC41')) and I did not get the emoji. running .text = String(charArrayOf('\uD83D', '\uDC41', 65039.toChar())) I get the emoji. and running VS15 .text = String(charArrayOf('\uD83D', '\uDC41', 65038.toChar())) I get no emoji as expected.Tallyman
M
3

Conclusion: By default, the text style will be used, unless these are followed by the U+FE0F variation selector.

This can be validated using the following method:

Case 1: Return false on all Android versions.

EmojiCompat.get().hasEmojiGlyph(String(charArrayOf('\uD83D', '\uDC41')))

Case 2: Return true on Android API versions >=18

EmojiCompat.get().hasEmojiGlyph(String(charArrayOf('\uD83D', '\uDC41', 65039.toChar())))

Solution: .setUseEmojiAsDefaultStyle(true)

class App : Application() {
    override fun onCreate() {
        super.onCreate()
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
        EmojiCompat.init(
            FontRequestEmojiCompatConfig(
                this,
                FontRequest(
                    "com.google.android.gms.fonts",
                    "com.google.android.gms",
                    "Noto Color Emoji Compat",
                    R.array.com_google_android_gms_fonts_certs
                )
            ).setReplaceAll(true)
                .setUseEmojiAsDefaultStyle(true)
                .registerInitCallback(object : EmojiCompat.InitCallback() {
                    override fun onInitialized() {
                        super.onInitialized()
                        Toast.makeText(this@App, "EmojiCompat was initialized", LENGTH_SHORT).show()
                    }

                    override fun onFailed(throwable: Throwable?) {
                        super.onFailed(throwable)
                        throw RuntimeException(throwable)
                    }
                })
        )
    }
}

Tested on Android API 19:

enter image description here

Mouthy answered 20/12, 2020 at 0:14 Comment(3)
You rock, simple and effective solution!Tallyman
Thank you! I appreciate the way you presented the problem. Demo Github project was very helpful.Mouthy
setUseEmojiAsDefaultStyle documentation's says "Determines whether EmojiCompat should use the emoji presentation style for emojis that have text style as default." which means even numbers and some special char won't be represented as text but rather as emoji, this is nice if it's the wanted behaviour but if not this solution can be pretty ugly cause you'll have to define a whole list of exception emojiCasals

© 2022 - 2024 — McMap. All rights reserved.