Skip to content

Commit

Permalink
Added SystemEmojiDrawable to render system emoji, using EmojiCompat2 …
Browse files Browse the repository at this point in the history
…to ensure missing glyphs are filled in.
  • Loading branch information
danbrun committed Feb 21, 2024
1 parent 5c6f146 commit 8a36eeb
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 1 deletion.
1 change: 1 addition & 0 deletions app/build.gradle.kts
Expand Up @@ -521,6 +521,7 @@ dependencies {
implementation(libs.androidx.profileinstaller)
implementation(libs.androidx.asynclayoutinflater)
implementation(libs.androidx.asynclayoutinflater.appcompat)
implementation(libs.androidx.emoji2)
implementation(libs.firebase.messaging) {
exclude(group = "com.google.firebase", module = "firebase-core")
exclude(group = "com.google.firebase", module = "firebase-analytics")
Expand Down
Expand Up @@ -23,6 +23,7 @@
import org.thoughtcrime.securesms.emoji.EmojiPageCache;
import org.thoughtcrime.securesms.emoji.EmojiSource;
import org.thoughtcrime.securesms.emoji.JumboEmoji;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.DeviceProperties;
import org.thoughtcrime.securesms.util.FutureTaskListener;

Expand Down Expand Up @@ -121,6 +122,10 @@ public class EmojiProvider {
return null;
}

if (SignalStore.settings().isPreferSystemEmoji()) {
return new SystemEmojiDrawable(drawInfo.getEmoji());
}

final int lowMemoryDecodeScale = DeviceProperties.isLowMemoryDevice(context) ? 2 : 1;
final EmojiSource source = EmojiSource.getLatest();
final EmojiDrawable drawable = new EmojiDrawable(source, drawInfo, lowMemoryDecodeScale);
Expand Down Expand Up @@ -202,6 +207,10 @@ public void onFailure(ExecutionException exception) {
return null;
}

if (SignalStore.settings().isPreferSystemEmoji()) {
return new SystemEmojiDrawable(drawInfo.getEmoji());
}

final int lowMemoryDecodeScale = DeviceProperties.isLowMemoryDevice(context) ? 2 : 1;
final EmojiSource source = EmojiSource.getLatest();
final EmojiDrawable drawable = new EmojiDrawable(source, drawInfo, lowMemoryDecodeScale);
Expand Down
@@ -0,0 +1,69 @@
package org.thoughtcrime.securesms.components.emoji

import android.graphics.Canvas
import android.graphics.ColorFilter
import android.graphics.Matrix
import android.graphics.PixelFormat
import android.graphics.Rect
import android.graphics.RectF
import android.graphics.drawable.Drawable
import android.os.Build
import android.text.Layout
import android.text.StaticLayout
import android.text.TextPaint
import androidx.core.graphics.toRectF
import androidx.core.graphics.withMatrix
import androidx.emoji2.text.EmojiCompat

/**
* [Drawable] that renders an emoji via the system font for available glyphs and EmojiCompat for
* missing glyphs.
*/
class SystemEmojiDrawable(emoji: CharSequence) : Drawable() {

private val emojiLayout: StaticLayout = getStaticLayout(getProcessedEmoji(emoji))
private val transform: Matrix = Matrix()

override fun onBoundsChange(bounds: Rect) {
super.onBoundsChange(bounds)
transform.setRectToRect(emojiLayout.getBounds(), bounds.toRectF(), Matrix.ScaleToFit.CENTER)
}

override fun draw(canvas: Canvas) {
canvas.withMatrix(transform) {
emojiLayout.draw(canvas)
}
}

override fun setAlpha(alpha: Int) {}

override fun setColorFilter(colorFilter: ColorFilter?) {}

@Deprecated(
"Deprecated in Java",
ReplaceWith("PixelFormat.TRANSLUCENT", "android.graphics.PixelFormat")
)
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT

companion object {
private val textPaint: TextPaint = TextPaint()

private fun getStaticLayout(emoji: CharSequence): StaticLayout =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
StaticLayout.Builder.obtain(emoji, 0, emoji.length, textPaint, Int.MAX_VALUE).build()
} else {
@Suppress("DEPRECATION")
StaticLayout(emoji, textPaint, Int.MAX_VALUE, Layout.Alignment.ALIGN_NORMAL, 0f, 0f, true)
}

private fun getProcessedEmoji(emoji: CharSequence): CharSequence =
try {
EmojiCompat.get().process(emoji) ?: emoji
} catch (e: IllegalStateException) {
emoji
}

private fun StaticLayout.getBounds(): RectF =
RectF(getLineLeft(0), 0f, getLineRight(0), getLineDescent(0) - getLineAscent(0).toFloat())
}
}
Expand Up @@ -2,4 +2,4 @@ package org.thoughtcrime.securesms.components.emoji.parsing

import org.thoughtcrime.securesms.emoji.EmojiPage

data class EmojiDrawInfo(val page: EmojiPage, val index: Int, private val emoji: String, val rawEmoji: String?, val jumboSheet: String?)
data class EmojiDrawInfo(val page: EmojiPage, val index: Int, val emoji: String, val rawEmoji: String?, val jumboSheet: String?)
1 change: 1 addition & 0 deletions dependencies.gradle.kts
Expand Up @@ -93,6 +93,7 @@ dependencyResolutionManagement {
library("androidx-profileinstaller", "androidx.profileinstaller:profileinstaller:1.2.2")
library("androidx-asynclayoutinflater", "androidx.asynclayoutinflater:asynclayoutinflater:1.1.0-alpha01")
library("androidx-asynclayoutinflater-appcompat", "androidx.asynclayoutinflater:asynclayoutinflater-appcompat:1.1.0-alpha01")
library("androidx-emoji2", "androidx.emoji2:emoji2:1.4.0")

// Material
library("material-material", "com.google.android.material:material:1.8.0")
Expand Down

0 comments on commit 8a36eeb

Please sign in to comment.