Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Miquel Beltran - No More □ (tofu) Mastering Emoji on Android

Miquel Beltran - No More □ (tofu) Mastering Emoji on Android

droidcon Berlin

July 17, 2018
Tweet

More Decks by droidcon Berlin

Other Decks in Programming

Transcript

  1. Why Emoji matters? What problems do Android developers face? What

    solutions do we have? Is EmojiCompat the greatest thing ever?
  2. Emotions Source: People interpret the same emoji in completely different

    ways https://www.theverge.com/2016/4/11/11406944/emoji-meaning-difference-ios-android
  3. Extra-short-intro to Unicode Hello U+0048 U+0065 U+006C U+006C U+006F Unicode:

    Single character set that contains ALL characters of the Universe Each character maps to a Codepoint A Codepoint may be represented in memory differently! Codepoint UTF-8 UTF-16 H U+0048 48 0048 U+1F602 F0 9F 98 82 D83D DE02
  4. How Emoji works Emoji: Graphic representation of one or more

    Unicode chars (Codepoints) "Face With Tears of Joy” U+1F602 val emoji = "\uD83D\uDE02"
  5. How Emoji works “Woman Technologist: Medium-Dark Skin Tone” val emoji

    = “\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDCBB" U+1F469 U+1F3FE U+200D U+1F4BB
  6. How long is an Emoji? Challenge: How many “Woman Technologist:

    Medium-Dark Skin Tone” Emojis can you fit on a Tweet? A: 280 B: 140 C: 40 Solution: 40 280 / 7 = 40
  7. How long is an Emoji? —> Improvement emoji.length = 7

    emoji.codePointCount(0, emoji.length) = 4 val emoji = “\uD83D\uDC69\uD83C\uDFFE\u200D\uD83D\uDCBB"
  8. How long is an Emoji? —> Improvement val it =

    BreakIterator.getCharacterInstance() it.setText(emoji) var count = 0 while (it.next() != BreakIterator.DONE) { count++ } count = 3 on API 23 count = 1 on API 25
  9. Let’s look at three solutions Custom solution: Images and Spans

    Custom solution: Font file Using EmojiCompat
  10. Images and Spans Strategy: 1. Find an Emoji on a

    String 2. Replace with an ImageSpan 3. Repeat for the whole String
  11. Finding Emoji on Strings Get a nice dictionary: EmojiOne “emoji.json”:

    1.38 MB! Fast JSON parsing: com.jsoniter —> but you won’t need to Efficient pattern matching —> Regular Expression
  12. Emoji assets Download: emojione/emojione-assets • Free: PNG 32px, 64px, 128px

    • Paid: SVG and larger PNG Example: SLICE OF PIZZA (U+1F355) —> 1f355.png
  13. Matching and displaying val PATTERN = “\\ud83c\\udf55".toRegex() val matches =

    PATTERN.findAll(text) for (match in matches) { spannableString.setSpan( ImageSpan(context, R.drawable.emoji_1f355), match.range.start, match.range.endInclusive + 1, SpannableString.SPAN_INCLUSIVE_INCLUSIVE ) } Solution: DynamicDrawableSpan (and resize the drawable)
  14. Custom font file Strategy: 1. Include font file with Emoji

    2. Set font file containing Emoji to TextView 3. Set text to TextView
  15. Custom font file: Setup 1. Download Android font 2. Place

    in assets/fonts Download: https://www.emojione.com/download
  16. Custom font file: Hold on… textView.text = "Numbers: 1 2

    3 4" Solution: Parse Emoji and create TypefaceSpans
  17. EmojiCompat: Setup (downloadable) val fontRequest = FontRequest( "com.google.android.gms.fonts", "com.google.android.gms", "Noto

    Color Emoji Compat", R.array.com_google_android_gms_fonts_certs) val config = FontRequestEmojiCompatConfig(this, fontRequest) EmojiCompat.init(config) Init takes 150 ms! But happens asynchronously
  18. EmojiCompat: Setup (downloadable) Downloadable fonts get updated automatically! Find it

    in data/data/com.google.android.gms/files/fonts/opentype Noto_Color_Emoji_Compat-400-100_0-0_0.ttf Version 2.003;GOOG;noto-emoji:20171030:a5efe6ca61db
  19. EmojiCompat: Handling init delay EmojiCompat.get().registerInitCallback(object : EmojiCompat.InitCallback() { override fun

    onInitialized() { textView.text = EmojiCompat.get().process(string) } override fun onFailed(throwable: Throwable?) { // handle error? textView.text = string } } )