Emoji Compatibility

The EmojiCompat support library aims to keep Android devices up to date with the latest emoji. It prevents your app from showing missing emoji characters in the form of ☐, which indicates that your device does not have a font to display the text. By using the EmojiCompat support library, your app users do not need to wait for Android OS updates to get the latest emoji.

Devices showing emoji
Figure 1. Emoji comparison

Refer to the following related resources:

How does EmojiCompat work?

The EmojiCompat support library provides classes to implement backward-compatible emoji support on devices running Android 4.4 (API level 19) and higher. You can configure EmojiCompat with either bundled or downloadable fonts. For more information about configuration, refer to the following sections:

EmojiCompat identifies emoji for a given CharSequence, replaces them with EmojiSpans, if required, and finally renders the emoji glyphs. Figure 2 demonstrates the process.

EmojiCompat process
Figure 2. EmojiCompat process

Downloadable fonts configuration

The downloadable fonts configuration uses the Downloadable Fonts support library feature to download an emoji font. It also updates the necessary emoji metadata that the EmojiCompat support library needs to keep up with the latest versions of the Unicode specification.

Adding support library dependency

To use the EmojiCompat support library, you must modify your app project's classpath dependencies within your development environment.

To add a support library to your application project:

  1. Open the build.gradle file of your application.
  2. Add the support library to the dependencies section.

Groovy

dependencies {
    ...
    implementation "androidx.emoji:emoji:28.0.0"
}

Kotlin

dependencies {
    ...
    implementation("androidx.emoji:emoji:28.0.0")
}

Initializing the downloadable font configuration

You need to initialize EmojiCompat to load the metadata and the typeface. Since initialization can take some time, the initialization process runs on a background thread.

To initialize EmojiCompat with the downloadable font configuration, perform the following steps:

  1. Create an instance of the FontRequest class and provide the font provider authority, the font provider package, the font query, and a list of sets of hashes for the certificate. For more information about FontRequest, refer to the Using Downloadable Fonts programmatically section in the Downloadable Fonts documentation.
  2. Create an instance of FontRequestEmojiCompatConfig and provide instances of Context and FontRequest.
  3. Initialize EmojiCompat by calling the init() method and pass the instance of FontRequestEmojiCompatConfig.
  4. Kotlin

    class MyApplication : Application() {
    
        override fun onCreate() {
            super.onCreate()
            val fontRequest = FontRequest(
                    "com.example.fontprovider",
                    "com.example",
                    "emoji compat Font Query",
                    CERTIFICATES
            )
            val config = FontRequestEmojiCompatConfig(this, fontRequest)
            EmojiCompat.init(config)
        }
    }
    

    Java

    public class MyApplication extends Application {
      @Override
       public void onCreate() {
         super.onCreate();
         FontRequest fontRequest = new FontRequest(
           "com.example.fontprovider",
           "com.example",
           "emoji compat Font Query",
           CERTIFICATES);
         EmojiCompat.Config config = new FontRequestEmojiCompatConfig(this, fontRequest);
         EmojiCompat.init(config);
       }
    }
    
  5. Use EmojiCompat widgets in layout XMLs. If you are using AppCompat, refer to the Using EmojiCompat widgets with AppCompat section.
  6. <android.support.text.emoji.widget.EmojiTextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
    
    <android.support.text.emoji.widget.EmojiEditText
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
    
    <android.support.text.emoji.widget.EmojiButton
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
    

For more information about how to configure EmojiCompat with the downloadable font configuration, go to Emoji Compatibility sample app Java | Kotlin.

Library components

Library components in EmojiCompat process
Figure 3. Library components in the EmojiCompat process
Widgets: EmojiEditText, EmojiTextView, EmojiButton
Default widget implementations to use EmojiCompat with TextView, EditText, and Button.
EmojiCompat
Main public surface for the support library. It performs all the external calls and coordinates with the other parts of the system.
EmojiCompat.Config
Configures the singleton instance to be created.
EmojiSpan
A ReplacementSpan subclass that replaces the character (sequences) and renders the glyph.
EmojiCompat Font
EmojiCompat uses a font to display emoji. This font is a modified version of the Android Emoji font. The font is modified as follows:
  • To provide backward compatibility to render emoji, all emoji characters are represented with a single Unicode code point in Unicode’s Supplemental Private Use Area-A starting with U+F0001.
  • Extra emoji metadata is inserted in a binary format into the font and is parsed at runtime by EmojiCompat. The data is embedded in the font’s meta table, with the private tag Emji.

Configuration options

You can use the EmojiCompat instance to modify EmojiCompat behavior. You can use the following methods from the base class to set the configuration:

Kotlin

val config = FontRequestEmojiCompatConfig(...)
        .setReplaceAll(true)
        .setEmojiSpanIndicatorEnabled(true)
        .setEmojiSpanIndicatorColor(Color.GREEN)
        .registerInitCallback(object: EmojiCompat.InitCallback() {
            ...
        })

Java

EmojiCompat.Config config = new FontRequestEmojiCompatConfig(...)
       .setReplaceAll(true)
       .setEmojiSpanIndicatorEnabled(true)
       .setEmojiSpanIndicatorColor(Color.GREEN)
       .registerInitCallback(new InitCallback() {...})

Adding initialization listeners

EmojiCompat and EmojiCompat classes provide registerInitCallback() and unregisterInitCallback() methods to register an initialization callback. To use these methods, create an instance of the EmojiCompat.InitCallback class. Call these methods and pass the instance of the EmojiCompat.InitCallback class. When the initialization of the EmojiCompat support library is successful, the EmojiCompat class calls the onInitialized() method. If the library fails to initialize, the EmojiCompat class calls the onFailed() method.

To check the initialization state at any point, call the getLoadState() method. It returns one of the following values: LOAD_STATE_LOADING, LOAD_STATE_SUCCEEDED, or LOAD_STATE_FAILED.

Using EmojiCompat with AppCompat widgets

If you are using AppCompat widgets, you can use EmojiCompat widgets that extend from AppCompat widgets.

  1. Add the support library to the dependencies section.

    Groovy

    dependencies {
        ...
        implementation "androidx.emoji:emoji-bundled:$version"
    }
    

    Kotlin

          dependencies {
              implementation("androidx.emoji:emoji-appcompat:$version")
          }
          

    Groovy

          dependencies {
              implementation "androidx.emoji:emoji-appcompat:$version"
          }
          
  2. Use EmojiCompat AppCompat Widget widgets in layout XMLs.
  3. <android.support.text.emoji.widget.EmojiAppCompatTextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
    
    <android.support.text.emoji.widget.EmojiAppCompatEditText
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
    
    <android.support.text.emoji.widget.EmojiAppCompatButton
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
    

Bundled fonts configuration

The EmojiCompat support library is also available in a bundled font version. This package includes the font with the embedded metadata. The package also includes a BundledEmojiCompatConfig that uses the AssetManager to load the metadata and fonts.

Note: The size of the font is in multiple megabytes.

Adding support library dependency

To use the EmojiCompat support library with bundled font configuration, you must modify your app project's classpath dependencies within your development environment.

To add a support library to your application project:

  1. Open the build.gradle file of your application.
  2. Add the support library to the dependencies section.

Groovy

dependencies {
    ...
    implementation "androidx.emoji:emoji:28.0.0"
}

Kotlin

dependencies {
    ...
    implementation("androidx.emoji:emoji:28.0.0")
}

Using bundled fonts to configure EmojiCompat

To use bundled fonts to configure EmojiCompat, perform the following steps:

  1. Use BundledEmojiCompatConfig to create an instance of EmojiCompat and provide an instance of Context.
  2. Call the init() method to initialize EmojiCompat and pass the instance of BundledEmojiCompatConfig.

Kotlin

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        val config = BundledEmojiCompatConfig(this)
        EmojiCompat.init(config)
    }
}

Java

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        EmojiCompat.Config config = new BundledEmojiCompatConfig(this);
        EmojiCompat.init(config);
        ...
    }
}

Using EmojiCompat without widgets

EmojiCompat uses EmojiSpan to render correct images. Therefore, it has to convert any given CharSequence into Spanned instances with EmojiSpans. The EmojiCompat class provides a method to convert CharSequences into Spanned instances with EmojiSpans. Using this method, you can process and cache the processed instances instead of the raw string, which improves the performance of your application.

Kotlin

val processed = EmojiCompat.get().process("neutral face \uD83D\uDE10")

Java

CharSequence processed = EmojiCompat.get().process("neutral face \uD83D\uDE10");

Using EmojiCompat for IMEs

Using the EmojiCompat support library, keyboards can render the emoji supported by the application they are interacting with. IMEs can use the hasEmojiGlyph() method to check if EmojiCompat is capable of rendering an emoji. This method takes a CharSequence of an emoji and returns true if EmojiCompat can detect and render the emoji.

The keyboard can also check the version of the EmojiCompat support library that the app supports to determine which emoji to render in the palette. To check the version, if available, the keyboard needs to check whether the following keys exist in the EditorInfo.extras bundle:

After receiving the keys in the EditorInfo.extras bundle, the keyboard can use the hasEmojiGlyph() method, where metadataVersion is the value for EDITOR_INFO_METAVERSION_KEY, to check whether the app can render a specific emoji.

Using EmojiCompat with custom widgets

You can always use the process() method to preprocess the CharSequence in your app and add it to any widget that can render Spanned instances; for example, TextView. In addition, EmojiCompat provides the following widget helper classes to let you enrich your custom widgets with emoji support with minimum effort.

Sample TextView

Kotlin

class MyTextView(context: Context) : AppCompatTextView(context) {

    private val emojiTextViewHelper: EmojiTextViewHelper by lazy(LazyThreadSafetyMode.NONE) {
        EmojiTextViewHelper(this).apply {
            updateTransformationMethod()
        }
    }

    override fun setFilters(filters: Array<InputFilter>) {
        super.setFilters(emojiTextViewHelper.getFilters(filters))
    }

    override fun setAllCaps(allCaps: Boolean) {
        super.setAllCaps(allCaps)
        emojiTextViewHelper.setAllCaps(allCaps)
    }
}

Java

public class MyTextView extends AppCompatTextView {
   ...
   public MyTextView(Context context) {
       super(context);
       init();
   }
   ...
   private void init() {
       getEmojiTextViewHelper().updateTransformationMethod();
   }

   @Override
   public void setFilters(InputFilter[] filters) {
       super.setFilters(getEmojiTextViewHelper().getFilters(filters));
   }

   @Override
   public void setAllCaps(boolean allCaps) {
       super.setAllCaps(allCaps);
       getEmojiTextViewHelper().setAllCaps(allCaps);
   }

   private EmojiTextViewHelper getEmojiTextViewHelper() {
       ...
   }
}
Sample EditText

Kotlin

class MyEditText(context: Context) : AppCompatEditText(context) {

    private val emojiEditTextHelper: EmojiEditTextHelper by lazy(LazyThreadSafetyMode.NONE) {
        EmojiEditTextHelper(this).also {
            super.setKeyListener(it.getKeyListener(keyListener))
        }
    }

    override fun setKeyListener(input: KeyListener?) {
        input?.also {
            super.setKeyListener(emojiEditTextHelper.getKeyListener(it))
        }
    }

    override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection {
        val inputConnection: InputConnection = super.onCreateInputConnection(outAttrs)
        return emojiEditTextHelper.onCreateInputConnection(
                inputConnection,
                outAttrs
        ) as InputConnection
    }
}

Java

public class MyEditText extends AppCompatEditText {
   ...
   public MyEditText(Context context) {
       super(context);
       init();
   }
   ...
   private void init() {
       super.setKeyListener(getEmojiEditTextHelper().getKeyListener(getKeyListener()));
   }

   @Override
   public void setKeyListener(android.text.method.KeyListener keyListener) {
       super.setKeyListener(getEmojiEditTextHelper().getKeyListener(keyListener));
   }

   @Override
   public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
       InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
       return getEmojiEditTextHelper().onCreateInputConnection(inputConnection, outAttrs);
   }

   private EmojiEditTextHelper getEmojiEditTextHelper() {
       ...
   }
}

Frequently asked questions

  • How do I initiate the font download?
  • The emoji fonts are downloaded on first request, if they do not exist on the device. The download scheduling is transparent to the app.

  • How much time does it take to initialize?
  • After the font is downloaded, it takes approximately 150 milliseconds to initialize EmojiCompat.

  • How much memory does the EmojiCompat support library use?
  • Currently, the data structure to find the emoji is loaded in the app’s memory and uses around 200KB.

  • Can I use EmojiCompat for a custom TextView?
  • Yes. EmojiCompat provides helper classes for custom widgets. It is also possible to preprocess a given string and convert it to Spanned. For more information about widget helper classes, refer to the Using EmojiCompat with custom widgets section.

  • What happens if I add widgets in layout XMLs on devices that run on Android 4.4 (API level 19) or lower?
  • You can include the EmojiCompat support library or its widgets in your applications that support devices running Android 4.4 (API level 19) or lower. However, if a device runs on an Android version prior to API level 19, EmojiCompat and its widgets are in a "no operation" state. This means that EmojiTextView behaves exactly like a regular TextView. EmojiCompat instance; it immediately gets into a LOAD_STATE_SUCCEEDED state when you call the init() method.

Additional resources

For additional information on using the EmojiCompat library, watch EmojiCompat.