Loading packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt +35 −14 Original line number Diff line number Diff line Loading @@ -24,12 +24,30 @@ import android.graphics.Canvas import android.graphics.Typeface import android.graphics.fonts.Font import android.text.Layout import android.text.TextPaint import android.util.LruCache private const val DEFAULT_ANIMATION_DURATION: Long = 300 private const val TYPEFACE_CACHE_MAX_ENTRIES = 5 typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit interface TypefaceVariantCache { fun getTypefaceForVariant(fvar: String, targetPaint: TextPaint): Typeface? } class TypefaceVariantCacheImpl() : TypefaceVariantCache { private val cache = LruCache<String, Typeface>(TYPEFACE_CACHE_MAX_ENTRIES) override fun getTypefaceForVariant(fvar: String, targetPaint: TextPaint): Typeface? { cache.get(fvar)?.let { return it } targetPaint.fontVariationSettings = fvar return targetPaint.typeface?.also { cache.put(fvar, it) } } } /** * This class provides text animation between two styles. * Loading @@ -56,9 +74,19 @@ typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit * ``` * </code> </pre> */ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) { class TextAnimator( layout: Layout, private val invalidateCallback: () -> Unit, ) { var typefaceCache: TypefaceVariantCache = TypefaceVariantCacheImpl() get() = field set(value) { field = value textInterpolator.typefaceCache = value } // Following two members are for mutable for testing purposes. public var textInterpolator: TextInterpolator = TextInterpolator(layout) public var textInterpolator: TextInterpolator = TextInterpolator(layout, typefaceCache) public var animator: ValueAnimator = ValueAnimator.ofFloat(1f).apply { duration = DEFAULT_ANIMATION_DURATION Loading @@ -68,9 +96,7 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) { } addListener( object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator?) { textInterpolator.rebase() } override fun onAnimationEnd(animation: Animator?) = textInterpolator.rebase() override fun onAnimationCancel(animation: Animator?) = textInterpolator.rebase() } ) Loading Loading @@ -116,8 +142,6 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) { private val fontVariationUtils = FontVariationUtils() private val typefaceCache = LruCache<String, Typeface>(TYPEFACE_CACHE_MAX_ENTRIES) fun updateLayout(layout: Layout) { textInterpolator.layout = layout } Loading Loading @@ -220,12 +244,8 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) { } if (!fvar.isNullOrBlank()) { textInterpolator.targetPaint.typeface = typefaceCache.get(fvar) ?: run { textInterpolator.targetPaint.fontVariationSettings = fvar textInterpolator.targetPaint.typeface?.also { typefaceCache.put(fvar, textInterpolator.targetPaint.typeface) } } textInterpolator.targetPaint.typeface = typefaceCache.getTypefaceForVariant(fvar, textInterpolator.targetPaint) } if (color != null) { Loading Loading @@ -304,7 +324,8 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) { weight = weight, width = width, opticalSize = opticalSize, roundness = roundness,) roundness = roundness, ) setTextStyle( fvar = fvar, textSize = textSize, Loading packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt +4 −2 Original line number Diff line number Diff line Loading @@ -28,8 +28,10 @@ import com.android.internal.graphics.ColorUtils import java.lang.Math.max /** Provide text style linear interpolation for plain text. */ class TextInterpolator(layout: Layout) { class TextInterpolator( layout: Layout, var typefaceCache: TypefaceVariantCache, ) { /** * Returns base paint used for interpolation. * Loading packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt +18 −11 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.text.TextPaint import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import java.io.File Loading Loading @@ -64,6 +65,7 @@ private val END_PAINT = TextPaint(PAINT).apply { @RunWith(AndroidTestingRunner::class) @SmallTest class TextInterpolatorTest : SysuiTestCase() { lateinit var typefaceCache: TypefaceVariantCache private fun makeLayout( text: String, Loading @@ -75,11 +77,16 @@ class TextInterpolatorTest : SysuiTestCase() { .setTextDirection(dir).build() } @Before fun setup() { typefaceCache = TypefaceVariantCacheImpl() } @Test fun testStartState() { val layout = makeLayout(TEXT, PAINT) val interp = TextInterpolator(layout) val interp = TextInterpolator(layout, typefaceCache) interp.basePaint.set(START_PAINT) interp.onBasePaintModified() Loading @@ -98,7 +105,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testEndState() { val layout = makeLayout(TEXT, PAINT) val interp = TextInterpolator(layout) val interp = TextInterpolator(layout, typefaceCache) interp.basePaint.set(START_PAINT) interp.onBasePaintModified() Loading @@ -116,7 +123,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testMiddleState() { val layout = makeLayout(TEXT, PAINT) val interp = TextInterpolator(layout) val interp = TextInterpolator(layout, typefaceCache) interp.basePaint.set(START_PAINT) interp.onBasePaintModified() Loading @@ -138,7 +145,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testRebase() { val layout = makeLayout(TEXT, PAINT) val interp = TextInterpolator(layout) val interp = TextInterpolator(layout, typefaceCache) interp.basePaint.set(START_PAINT) interp.onBasePaintModified() Loading @@ -160,7 +167,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testBidi_LTR() { val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.LTR) val interp = TextInterpolator(layout) val interp = TextInterpolator(layout, typefaceCache) interp.basePaint.set(START_PAINT) interp.onBasePaintModified() Loading @@ -180,7 +187,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testBidi_RTL() { val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL) val interp = TextInterpolator(layout) val interp = TextInterpolator(layout, typefaceCache) interp.basePaint.set(START_PAINT) interp.onBasePaintModified() Loading @@ -200,7 +207,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testGlyphCallback_Empty() { val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL) val interp = TextInterpolator(layout).apply { val interp = TextInterpolator(layout, typefaceCache).apply { glyphFilter = { glyph, progress -> } } Loading @@ -222,7 +229,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testGlyphCallback_Xcoordinate() { val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL) val interp = TextInterpolator(layout).apply { val interp = TextInterpolator(layout, typefaceCache).apply { glyphFilter = { glyph, progress -> glyph.x += 30f } Loading @@ -247,7 +254,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testGlyphCallback_Ycoordinate() { val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL) val interp = TextInterpolator(layout).apply { val interp = TextInterpolator(layout, typefaceCache).apply { glyphFilter = { glyph, progress -> glyph.y += 30f } Loading @@ -272,7 +279,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testGlyphCallback_TextSize() { val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL) val interp = TextInterpolator(layout).apply { val interp = TextInterpolator(layout, typefaceCache).apply { glyphFilter = { glyph, progress -> glyph.textSize += 10f } Loading @@ -297,7 +304,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testGlyphCallback_Color() { val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL) val interp = TextInterpolator(layout).apply { val interp = TextInterpolator(layout, typefaceCache).apply { glyphFilter = { glyph, progress -> glyph.color = Color.RED } Loading Loading
packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt +35 −14 Original line number Diff line number Diff line Loading @@ -24,12 +24,30 @@ import android.graphics.Canvas import android.graphics.Typeface import android.graphics.fonts.Font import android.text.Layout import android.text.TextPaint import android.util.LruCache private const val DEFAULT_ANIMATION_DURATION: Long = 300 private const val TYPEFACE_CACHE_MAX_ENTRIES = 5 typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit interface TypefaceVariantCache { fun getTypefaceForVariant(fvar: String, targetPaint: TextPaint): Typeface? } class TypefaceVariantCacheImpl() : TypefaceVariantCache { private val cache = LruCache<String, Typeface>(TYPEFACE_CACHE_MAX_ENTRIES) override fun getTypefaceForVariant(fvar: String, targetPaint: TextPaint): Typeface? { cache.get(fvar)?.let { return it } targetPaint.fontVariationSettings = fvar return targetPaint.typeface?.also { cache.put(fvar, it) } } } /** * This class provides text animation between two styles. * Loading @@ -56,9 +74,19 @@ typealias GlyphCallback = (TextAnimator.PositionedGlyph, Float) -> Unit * ``` * </code> </pre> */ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) { class TextAnimator( layout: Layout, private val invalidateCallback: () -> Unit, ) { var typefaceCache: TypefaceVariantCache = TypefaceVariantCacheImpl() get() = field set(value) { field = value textInterpolator.typefaceCache = value } // Following two members are for mutable for testing purposes. public var textInterpolator: TextInterpolator = TextInterpolator(layout) public var textInterpolator: TextInterpolator = TextInterpolator(layout, typefaceCache) public var animator: ValueAnimator = ValueAnimator.ofFloat(1f).apply { duration = DEFAULT_ANIMATION_DURATION Loading @@ -68,9 +96,7 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) { } addListener( object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator?) { textInterpolator.rebase() } override fun onAnimationEnd(animation: Animator?) = textInterpolator.rebase() override fun onAnimationCancel(animation: Animator?) = textInterpolator.rebase() } ) Loading Loading @@ -116,8 +142,6 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) { private val fontVariationUtils = FontVariationUtils() private val typefaceCache = LruCache<String, Typeface>(TYPEFACE_CACHE_MAX_ENTRIES) fun updateLayout(layout: Layout) { textInterpolator.layout = layout } Loading Loading @@ -220,12 +244,8 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) { } if (!fvar.isNullOrBlank()) { textInterpolator.targetPaint.typeface = typefaceCache.get(fvar) ?: run { textInterpolator.targetPaint.fontVariationSettings = fvar textInterpolator.targetPaint.typeface?.also { typefaceCache.put(fvar, textInterpolator.targetPaint.typeface) } } textInterpolator.targetPaint.typeface = typefaceCache.getTypefaceForVariant(fvar, textInterpolator.targetPaint) } if (color != null) { Loading Loading @@ -304,7 +324,8 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) { weight = weight, width = width, opticalSize = opticalSize, roundness = roundness,) roundness = roundness, ) setTextStyle( fvar = fvar, textSize = textSize, Loading
packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt +4 −2 Original line number Diff line number Diff line Loading @@ -28,8 +28,10 @@ import com.android.internal.graphics.ColorUtils import java.lang.Math.max /** Provide text style linear interpolation for plain text. */ class TextInterpolator(layout: Layout) { class TextInterpolator( layout: Layout, var typefaceCache: TypefaceVariantCache, ) { /** * Returns base paint used for interpolation. * Loading
packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt +18 −11 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.text.TextPaint import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import java.io.File Loading Loading @@ -64,6 +65,7 @@ private val END_PAINT = TextPaint(PAINT).apply { @RunWith(AndroidTestingRunner::class) @SmallTest class TextInterpolatorTest : SysuiTestCase() { lateinit var typefaceCache: TypefaceVariantCache private fun makeLayout( text: String, Loading @@ -75,11 +77,16 @@ class TextInterpolatorTest : SysuiTestCase() { .setTextDirection(dir).build() } @Before fun setup() { typefaceCache = TypefaceVariantCacheImpl() } @Test fun testStartState() { val layout = makeLayout(TEXT, PAINT) val interp = TextInterpolator(layout) val interp = TextInterpolator(layout, typefaceCache) interp.basePaint.set(START_PAINT) interp.onBasePaintModified() Loading @@ -98,7 +105,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testEndState() { val layout = makeLayout(TEXT, PAINT) val interp = TextInterpolator(layout) val interp = TextInterpolator(layout, typefaceCache) interp.basePaint.set(START_PAINT) interp.onBasePaintModified() Loading @@ -116,7 +123,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testMiddleState() { val layout = makeLayout(TEXT, PAINT) val interp = TextInterpolator(layout) val interp = TextInterpolator(layout, typefaceCache) interp.basePaint.set(START_PAINT) interp.onBasePaintModified() Loading @@ -138,7 +145,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testRebase() { val layout = makeLayout(TEXT, PAINT) val interp = TextInterpolator(layout) val interp = TextInterpolator(layout, typefaceCache) interp.basePaint.set(START_PAINT) interp.onBasePaintModified() Loading @@ -160,7 +167,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testBidi_LTR() { val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.LTR) val interp = TextInterpolator(layout) val interp = TextInterpolator(layout, typefaceCache) interp.basePaint.set(START_PAINT) interp.onBasePaintModified() Loading @@ -180,7 +187,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testBidi_RTL() { val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL) val interp = TextInterpolator(layout) val interp = TextInterpolator(layout, typefaceCache) interp.basePaint.set(START_PAINT) interp.onBasePaintModified() Loading @@ -200,7 +207,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testGlyphCallback_Empty() { val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL) val interp = TextInterpolator(layout).apply { val interp = TextInterpolator(layout, typefaceCache).apply { glyphFilter = { glyph, progress -> } } Loading @@ -222,7 +229,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testGlyphCallback_Xcoordinate() { val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL) val interp = TextInterpolator(layout).apply { val interp = TextInterpolator(layout, typefaceCache).apply { glyphFilter = { glyph, progress -> glyph.x += 30f } Loading @@ -247,7 +254,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testGlyphCallback_Ycoordinate() { val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL) val interp = TextInterpolator(layout).apply { val interp = TextInterpolator(layout, typefaceCache).apply { glyphFilter = { glyph, progress -> glyph.y += 30f } Loading @@ -272,7 +279,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testGlyphCallback_TextSize() { val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL) val interp = TextInterpolator(layout).apply { val interp = TextInterpolator(layout, typefaceCache).apply { glyphFilter = { glyph, progress -> glyph.textSize += 10f } Loading @@ -297,7 +304,7 @@ class TextInterpolatorTest : SysuiTestCase() { fun testGlyphCallback_Color() { val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL) val interp = TextInterpolator(layout).apply { val interp = TextInterpolator(layout, typefaceCache).apply { glyphFilter = { glyph, progress -> glyph.color = Color.RED } Loading