Cache Typeface for later animation
The Paint#setFontvariationSettings always creates new Typeface instance from scratch. To avoid unnecessary Typeface creation for the same weight variant, cache the Typeface and use it later same animation. Bug: 189867246 Test: atest TextAnimatorTest TextInterpolatorTest Change-Id: I67ca72f2c54ca9caf4bcf562557ac4f24b44f01e
This commit is contained in:
@@ -21,7 +21,9 @@ import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.TimeInterpolator
|
||||
import android.animation.ValueAnimator
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Typeface
|
||||
import android.text.Layout
|
||||
import android.util.SparseArray
|
||||
|
||||
private const val TAG_WGHT = "wght"
|
||||
private const val DEFAULT_ANIMATION_DURATION: Long = 300
|
||||
@@ -72,6 +74,8 @@ class TextAnimator(
|
||||
})
|
||||
}
|
||||
|
||||
private val typefaceCache = SparseArray<Typeface?>()
|
||||
|
||||
fun updateLayout(layout: Layout) {
|
||||
textInterpolator.layout = layout
|
||||
}
|
||||
@@ -120,7 +124,12 @@ class TextAnimator(
|
||||
textInterpolator.targetPaint.textSize = textSize
|
||||
}
|
||||
if (weight >= 0) {
|
||||
textInterpolator.targetPaint.fontVariationSettings = "'$TAG_WGHT' $weight"
|
||||
// Paint#setFontVariationSettings creates Typeface instance from scratch. To reduce the
|
||||
// memory impact, cache the typeface result.
|
||||
textInterpolator.targetPaint.typeface = typefaceCache.getOrElse(weight) {
|
||||
textInterpolator.targetPaint.fontVariationSettings = "'$TAG_WGHT' $weight"
|
||||
textInterpolator.targetPaint.typeface
|
||||
}
|
||||
}
|
||||
if (color != null) {
|
||||
textInterpolator.targetPaint.color = color
|
||||
@@ -155,3 +164,12 @@ class TextAnimator(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <V> SparseArray<V>.getOrElse(key: Int, defaultValue: () -> V): V {
|
||||
var v = get(key)
|
||||
if (v == null) {
|
||||
v = defaultValue()
|
||||
put(key, v)
|
||||
}
|
||||
return v
|
||||
}
|
||||
@@ -18,12 +18,14 @@ package com.android.keyguard
|
||||
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.ValueAnimator
|
||||
import android.graphics.Typeface
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.text.Layout
|
||||
import android.text.StaticLayout
|
||||
import android.text.TextPaint
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
@@ -140,4 +142,41 @@ class TextAnimatorTest : SysuiTestCase() {
|
||||
verify(animationEndCallback).run()
|
||||
verify(valueAnimator).removeListener(eq(captor.value))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCacheTypeface() {
|
||||
val layout = makeLayout("Hello, World", PAINT)
|
||||
val valueAnimator = mock(ValueAnimator::class.java)
|
||||
val textInterpolator = mock(TextInterpolator::class.java)
|
||||
val paint = TextPaint().apply {
|
||||
typeface = Typeface.createFromFile("/system/fonts/Roboto-Regular.ttf")
|
||||
}
|
||||
`when`(textInterpolator.targetPaint).thenReturn(paint)
|
||||
|
||||
val textAnimator = TextAnimator(layout, {}).apply {
|
||||
this.textInterpolator = textInterpolator
|
||||
this.animator = valueAnimator
|
||||
}
|
||||
|
||||
textAnimator.setTextStyle(
|
||||
weight = 400,
|
||||
animate = true
|
||||
)
|
||||
|
||||
val prevTypeface = paint.typeface
|
||||
|
||||
textAnimator.setTextStyle(
|
||||
weight = 700,
|
||||
animate = true
|
||||
)
|
||||
|
||||
assertThat(paint.typeface).isNotSameInstanceAs(prevTypeface)
|
||||
|
||||
textAnimator.setTextStyle(
|
||||
weight = 400,
|
||||
animate = true
|
||||
)
|
||||
|
||||
assertThat(paint.typeface).isSameInstanceAs(prevTypeface)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user