Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 083620f3 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Animate clock fonts with fewer discrete steps" into udc-dev am: 3c4b404c

parents 3d7a4bae 3c4b404c
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.animation

import android.graphics.fonts.Font
import android.graphics.fonts.FontVariationAxis
import android.util.Log
import android.util.LruCache
import android.util.MathUtils
import android.util.MathUtils.abs
@@ -114,6 +115,9 @@ class FontInterpolator {
        tmpInterpKey.set(start, end, progress)
        val cachedFont = interpCache[tmpInterpKey]
        if (cachedFont != null) {
            if (DEBUG) {
                Log.d(LOG_TAG, "[$progress] Interp. cache hit for $tmpInterpKey")
            }
            return cachedFont
        }

@@ -159,6 +163,9 @@ class FontInterpolator {
        val axesCachedFont = verFontCache[tmpVarFontKey]
        if (axesCachedFont != null) {
            interpCache.put(InterpKey(start, end, progress), axesCachedFont)
            if (DEBUG) {
                Log.d(LOG_TAG, "[$progress] Axis cache hit for $tmpVarFontKey")
            }
            return axesCachedFont
        }

@@ -168,6 +175,9 @@ class FontInterpolator {
        val newFont = Font.Builder(start).setFontVariationSettings(newAxes.toTypedArray()).build()
        interpCache.put(InterpKey(start, end, progress), newFont)
        verFontCache.put(VarFontKey(start, newAxes), newFont)
        if (DEBUG) {
            Log.d(LOG_TAG, "[$progress] Cache MISS for $tmpInterpKey / $tmpVarFontKey")
        }
        return newFont
    }

@@ -233,6 +243,8 @@ class FontInterpolator {
        (v.coerceIn(min, max) / step).toInt() * step

    companion object {
        private const val LOG_TAG = "FontInterpolator"
        private val DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG)
        private val EMPTY_AXES = arrayOf<FontVariationAxis>()

        // Returns true if given two font instance can be interpolated.
+18 −5
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.graphics.fonts.Font
import android.graphics.fonts.FontVariationAxis
import android.text.Layout
import android.util.LruCache
import kotlin.math.roundToInt

private const val DEFAULT_ANIMATION_DURATION: Long = 300
private const val TYPEFACE_CACHE_MAX_ENTRIES = 5
@@ -63,9 +64,9 @@ class TypefaceVariantCacheImpl(
            return it
        }

        return TypefaceVariantCache
            .createVariantTypeface(baseTypeface, fvar)
            .also { cache.put(fvar, it) }
        return TypefaceVariantCache.createVariantTypeface(baseTypeface, fvar).also {
            cache.put(fvar, it)
        }
    }
}

@@ -74,7 +75,6 @@ class TypefaceVariantCacheImpl(
 *
 * Currently this class can provide text style animation for text weight and text size. For example
 * the simple view that draws text with animating text size is like as follows:
 *
 * <pre> <code>
 * ```
 *     class SimpleTextAnimation : View {
@@ -97,6 +97,7 @@ class TypefaceVariantCacheImpl(
 */
class TextAnimator(
    layout: Layout,
    numberOfAnimationSteps: Int? = null, // Only do this number of discrete animation steps.
    private val invalidateCallback: () -> Unit,
) {
    var typefaceCache: TypefaceVariantCache = TypefaceVariantCacheImpl(layout.paint.typeface)
@@ -112,7 +113,8 @@ class TextAnimator(
        ValueAnimator.ofFloat(1f).apply {
            duration = DEFAULT_ANIMATION_DURATION
            addUpdateListener {
                textInterpolator.progress = it.animatedValue as Float
                textInterpolator.progress =
                    calculateProgress(it.animatedValue as Float, numberOfAnimationSteps)
                invalidateCallback()
            }
            addListener(
@@ -123,6 +125,17 @@ class TextAnimator(
            )
        }

    private fun calculateProgress(animProgress: Float, numberOfAnimationSteps: Int?): Float {
        if (numberOfAnimationSteps != null) {
            // This clamps the progress to the nearest value of "numberOfAnimationSteps"
            // discrete values between 0 and 1f.
            return (animProgress * numberOfAnimationSteps).roundToInt() /
                numberOfAnimationSteps.toFloat()
        }

        return animProgress
    }

    sealed class PositionedGlyph {

        /** Mutable X coordinate of the glyph position relative from drawing offset. */
+3 −1
Original line number Diff line number Diff line
@@ -74,7 +74,8 @@ class AnimatableClockView @JvmOverloads constructor(
    private var onTextAnimatorInitialized: Runnable? = null

    @VisibleForTesting var textAnimatorFactory: (Layout, () -> Unit) -> TextAnimator =
        { layout, invalidateCb -> TextAnimator(layout, invalidateCb) }
        { layout, invalidateCb ->
            TextAnimator(layout, NUM_CLOCK_FONT_ANIMATION_STEPS, invalidateCb) }
    @VisibleForTesting var isAnimationEnabled: Boolean = true
    @VisibleForTesting var timeOverrideInMillis: Long? = null

@@ -567,6 +568,7 @@ class AnimatableClockView @JvmOverloads constructor(
        private const val CHARGE_ANIM_DURATION_PHASE_0: Long = 500
        private const val CHARGE_ANIM_DURATION_PHASE_1: Long = 1000
        private const val COLOR_ANIM_DURATION: Long = 400
        private const val NUM_CLOCK_FONT_ANIMATION_STEPS = 30

        // Constants for the animation
        private val MOVE_INTERPOLATOR = Interpolators.EMPHASIZED
+34 −45
Original line number Diff line number Diff line
@@ -26,18 +26,17 @@ import android.text.TextPaint
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import kotlin.math.ceil
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mockito.`when`
import org.mockito.Mockito.eq
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify

import kotlin.math.ceil
import org.mockito.Mockito.`when`

@RunWith(AndroidTestingRunner::class)
@SmallTest
@@ -56,15 +55,13 @@ class TextAnimatorTest : SysuiTestCase() {
        val paint = mock(TextPaint::class.java)
        `when`(textInterpolator.targetPaint).thenReturn(paint)

        val textAnimator = TextAnimator(layout, {}).apply {
        val textAnimator =
            TextAnimator(layout, null, {}).apply {
                this.textInterpolator = textInterpolator
                this.animator = valueAnimator
            }

        textAnimator.setTextStyle(
                weight = 400,
                animate = true
        )
        textAnimator.setTextStyle(weight = 400, animate = true)

        // If animation is requested, the base state should be rebased and the target state should
        // be updated.
@@ -88,15 +85,13 @@ class TextAnimatorTest : SysuiTestCase() {
        val paint = mock(TextPaint::class.java)
        `when`(textInterpolator.targetPaint).thenReturn(paint)

        val textAnimator = TextAnimator(layout, {}).apply {
        val textAnimator =
            TextAnimator(layout, null, {}).apply {
                this.textInterpolator = textInterpolator
                this.animator = valueAnimator
            }

        textAnimator.setTextStyle(
                weight = 400,
                animate = false
        )
        textAnimator.setTextStyle(weight = 400, animate = false)

        // If animation is not requested, the progress should be 1 which is end of animation and the
        // base state is rebased to target state by calling rebase.
@@ -118,7 +113,8 @@ class TextAnimatorTest : SysuiTestCase() {
        `when`(textInterpolator.targetPaint).thenReturn(paint)
        val animationEndCallback = mock(Runnable::class.java)

        val textAnimator = TextAnimator(layout, {}).apply {
        val textAnimator =
            TextAnimator(layout, null, {}).apply {
                this.textInterpolator = textInterpolator
                this.animator = valueAnimator
            }
@@ -144,34 +140,27 @@ class TextAnimatorTest : SysuiTestCase() {
        val layout = makeLayout("Hello, World", PAINT)
        val valueAnimator = mock(ValueAnimator::class.java)
        val textInterpolator = mock(TextInterpolator::class.java)
        val paint = TextPaint().apply {
        val paint =
            TextPaint().apply {
                typeface = Typeface.createFromFile("/system/fonts/Roboto-Regular.ttf")
            }
        `when`(textInterpolator.targetPaint).thenReturn(paint)

        val textAnimator = TextAnimator(layout, {}).apply {
        val textAnimator =
            TextAnimator(layout, null, {}).apply {
                this.textInterpolator = textInterpolator
                this.animator = valueAnimator
            }

        textAnimator.setTextStyle(
                weight = 400,
                animate = true
        )
        textAnimator.setTextStyle(weight = 400, animate = true)

        val prevTypeface = paint.typeface

        textAnimator.setTextStyle(
                weight = 700,
                animate = true
        )
        textAnimator.setTextStyle(weight = 700, animate = true)

        assertThat(paint.typeface).isNotSameInstanceAs(prevTypeface)

        textAnimator.setTextStyle(
                weight = 400,
                animate = true
        )
        textAnimator.setTextStyle(weight = 400, animate = true)

        assertThat(paint.typeface).isSameInstanceAs(prevTypeface)
    }