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

Commit 0a737d07 authored by Hawkwood Glazier's avatar Hawkwood Glazier
Browse files

Normalize TextInterpolator rebase operations

Bug: 401521058
Test: Manually verified edge case
Flag: com.android.systemui.shared.clock_reactive_variants
Change-Id: I2af270f72ce402798e56446102be2ac6a1d5ba27
parent 31d71959
Loading
Loading
Loading
Loading
+15 −4
Original line number Diff line number Diff line
@@ -82,6 +82,10 @@ class TypefaceVariantCacheImpl(var baseTypeface: Typeface, override val animatio
    }
}

interface TextAnimatorListener : TextInterpolatorListener {
    fun onInvalidate() {}
}

/**
 * This class provides text animation between two styles.
 *
@@ -110,13 +114,19 @@ class TypefaceVariantCacheImpl(var baseTypeface: Typeface, override val animatio
class TextAnimator(
    layout: Layout,
    private val typefaceCache: TypefaceVariantCache,
    private val invalidateCallback: () -> Unit = {},
    private val listener: TextAnimatorListener? = null,
) {
    @VisibleForTesting var textInterpolator = TextInterpolator(layout, typefaceCache)
    var textInterpolator = TextInterpolator(layout, typefaceCache, listener)
    @VisibleForTesting var createAnimator: () -> ValueAnimator = { ValueAnimator.ofFloat(1f) }

    var animator: ValueAnimator? = null

    val progress: Float
        get() = textInterpolator.progress

    val linearProgress: Float
        get() = textInterpolator.linearProgress

    val fontVariationUtils = FontVariationUtils()

    sealed class PositionedGlyph {
@@ -288,8 +298,9 @@ class TextAnimator(
            animator = buildAnimator(animation).apply { start() }
        } else {
            textInterpolator.progress = 1f
            textInterpolator.linearProgress = 1f
            textInterpolator.rebase()
            invalidateCallback()
            listener?.onInvalidate()
        }
    }

@@ -302,7 +313,7 @@ class TextAnimator(
            addUpdateListener {
                textInterpolator.progress = it.animatedValue as Float
                textInterpolator.linearProgress = it.currentPlayTime / it.duration.toFloat()
                invalidateCallback()
                listener?.onInvalidate()
            }

            addListener(
+17 −1
Original line number Diff line number Diff line
@@ -27,8 +27,19 @@ import android.util.MathUtils
import com.android.internal.graphics.ColorUtils
import java.lang.Math.max

interface TextInterpolatorListener {
    fun onPaintModified() {}

    fun onRebased() {}
}

/** Provide text style linear interpolation for plain text. */
class TextInterpolator(layout: Layout, var typefaceCache: TypefaceVariantCache) {
class TextInterpolator(
    layout: Layout,
    var typefaceCache: TypefaceVariantCache,
    private val listener: TextInterpolatorListener? = null,
) {

    /**
     * Returns base paint used for interpolation.
     *
@@ -136,6 +147,7 @@ class TextInterpolator(layout: Layout, var typefaceCache: TypefaceVariantCache)
     */
    fun onTargetPaintModified() {
        updatePositionsAndFonts(shapeText(layout, targetPaint), updateBase = false)
        listener?.onPaintModified()
    }

    /**
@@ -146,6 +158,7 @@ class TextInterpolator(layout: Layout, var typefaceCache: TypefaceVariantCache)
     */
    fun onBasePaintModified() {
        updatePositionsAndFonts(shapeText(layout, basePaint), updateBase = true)
        listener?.onPaintModified()
    }

    /**
@@ -204,6 +217,7 @@ class TextInterpolator(layout: Layout, var typefaceCache: TypefaceVariantCache)
     */
    fun rebase() {
        if (progress == 0f) {
            listener?.onRebased()
            return
        } else if (progress == 1f) {
            basePaint.set(targetPaint)
@@ -233,6 +247,8 @@ class TextInterpolator(layout: Layout, var typefaceCache: TypefaceVariantCache)
        }

        progress = 0f
        linearProgress = 0f
        listener?.onRebased()
    }

    /**
+8 −1
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import com.android.app.animation.Interpolators
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.animation.GlyphCallback
import com.android.systemui.animation.TextAnimator
import com.android.systemui.animation.TextAnimatorListener
import com.android.systemui.animation.TypefaceVariantCacheImpl
import com.android.systemui.customization.R
import com.android.systemui.log.core.LogLevel
@@ -100,7 +101,13 @@ constructor(
    @VisibleForTesting
    var textAnimatorFactory: (Layout, () -> Unit) -> TextAnimator = { layout, invalidateCb ->
        val cache = TypefaceVariantCacheImpl(layout.paint.typeface, NUM_CLOCK_FONT_ANIMATION_STEPS)
        TextAnimator(layout, cache, invalidateCb)
        TextAnimator(
            layout,
            cache,
            object : TextAnimatorListener {
                override fun onInvalidate() = invalidateCb()
            },
        )
    }

    // Used by screenshot tests to provide stability
+29 −19
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import android.graphics.Rect
import android.os.VibrationEffect
import android.text.Layout
import android.text.TextPaint
import android.util.AttributeSet
import android.util.Log
@@ -39,6 +38,7 @@ import com.android.app.animation.Interpolators
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.animation.GSFAxes
import com.android.systemui.animation.TextAnimator
import com.android.systemui.animation.TextAnimatorListener
import com.android.systemui.customization.R
import com.android.systemui.plugins.clocks.ClockFontAxisSetting
import com.android.systemui.plugins.clocks.ClockFontAxisSetting.Companion.replace
@@ -175,11 +175,6 @@ open class SimpleDigitalClockTextView(

    private val typefaceCache = clockCtx.typefaceCache.getVariantCache("")

    @VisibleForTesting
    var textAnimatorFactory: (Layout, () -> Unit) -> TextAnimator = { layout, invalidateCb ->
        TextAnimator(layout, typefaceCache, invalidateCb)
    }

    var verticalAlignment: VerticalAlignment = VerticalAlignment.BASELINE
    var horizontalAlignment: HorizontalAlignment = HorizontalAlignment.CENTER

@@ -247,7 +242,18 @@ open class SimpleDigitalClockTextView(
        val layout = this.layout
        if (layout != null) {
            if (!this::textAnimator.isInitialized) {
                textAnimator = textAnimatorFactory(layout, ::invalidate)
                textAnimator =
                    TextAnimator(
                        layout,
                        typefaceCache,
                        object : TextAnimatorListener {
                            override fun onInvalidate() = invalidate()

                            override fun onRebased() = updateTextBounds()

                            override fun onPaintModified() = updateTextBounds()
                        },
                    )
                setInterpolatorPaint()
            } else {
                textAnimator.updateLayout(layout)
@@ -272,7 +278,7 @@ open class SimpleDigitalClockTextView(
    override fun onDraw(canvas: Canvas) {
        logger.onDraw(textAnimator.textInterpolator.shapedText)

        val interpProgress = getInterpolatedProgress()
        val interpProgress = textAnimator.progress
        val interpBounds = getInterpolatedTextBounds(interpProgress)
        if (interpProgress != drawnProgress) {
            drawnProgress = interpProgress
@@ -336,7 +342,6 @@ open class SimpleDigitalClockTextView(
                interpolator = aodDozingInterpolator,
            ),
        )
        updateTextBoundsForTextAnimator()

        if (!isAnimated) {
            requestLayout()
@@ -367,11 +372,9 @@ open class SimpleDigitalClockTextView(
                            duration = CHARGE_ANIMATION_DURATION,
                        ),
                    )
                    updateTextBoundsForTextAnimator()
                },
            ),
        )
        updateTextBoundsForTextAnimator()
    }

    fun animateFidget(x: Float, y: Float) = animateFidget(0L)
@@ -401,11 +404,9 @@ open class SimpleDigitalClockTextView(
                            interpolator = FIDGET_INTERPOLATOR,
                        ),
                    )
                    updateTextBoundsForTextAnimator()
                },
            ),
        )
        updateTextBoundsForTextAnimator()
    }

    fun refreshText() {
@@ -428,12 +429,8 @@ open class SimpleDigitalClockTextView(
            id == R.id.MINUTE_SECOND_DIGIT
    }

    private fun getInterpolatedProgress(): Float {
        return textAnimator.animator?.let { it.animatedValue as Float } ?: 1f
    }

    /** Returns the interpolated text bounding rect based on interpolation progress */
    private fun getInterpolatedTextBounds(progress: Float = getInterpolatedProgress()): VRectF {
    private fun getInterpolatedTextBounds(progress: Float = textAnimator.progress): VRectF {
        if (progress <= 0f) {
            return prevTextBounds
        } else if (!textAnimator.isRunning || progress >= 1f) {
@@ -487,6 +484,15 @@ open class SimpleDigitalClockTextView(
            MeasureSpec.makeMeasureSpec(measureBounds.x.roundToInt(), mode.x),
            MeasureSpec.makeMeasureSpec(measureBounds.y.roundToInt(), mode.y),
        )

        logger.d({
            val size = VPointF.fromLong(long1)
            val mode = VPoint.fromLong(long2)
            "setInterpolatedSize(size=$size, mode=$mode)"
        }) {
            long1 = measureBounds.toLong()
            long2 = mode.toLong()
        }
    }

    /** Set the location of the view to match the interpolated text bounds */
@@ -514,6 +520,9 @@ open class SimpleDigitalClockTextView(
            targetRect.bottom.roundToInt(),
        )
        onViewBoundsChanged?.let { it(targetRect) }
        logger.d({ "setInterpolatedLocation(${VRectF.fromLong(long1)})" }) {
            long1 = targetRect.toLong()
        }
        return targetRect
    }

@@ -616,7 +625,8 @@ open class SimpleDigitalClockTextView(
     * rebase if previous animator is canceled so basePaint will store the state we transition from
     * and targetPaint will store the state we transition to
     */
    private fun updateTextBoundsForTextAnimator() {
    private fun updateTextBounds() {
        drawnProgress = null
        prevTextBounds = textAnimator.textInterpolator.basePaint.getTextBounds(text)
        targetTextBounds = textAnimator.textInterpolator.targetPaint.getTextBounds(text)
    }
+3 −3
Original line number Diff line number Diff line
@@ -55,9 +55,9 @@ class ClockLogger(private val view: View?, buffer: MessageBuffer, tag: String) :
    }

    fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        d({ "onLayout($bool1, ${VRect(long1.toULong())})" }) {
        d({ "onLayout($bool1, ${VRect.fromLong(long1)})" }) {
            bool1 = changed
            long1 = VRect(left, top, right, bottom).data.toLong()
            long1 = VRect(left, top, right, bottom).toLong()
        }
    }

@@ -116,7 +116,7 @@ class ClockLogger(private val view: View?, buffer: MessageBuffer, tag: String) :
    }

    fun animateFidget(x: Float, y: Float) {
        d({ "animateFidget(${VPointF(long1.toULong())})" }) { long1 = VPointF(x, y).data.toLong() }
        d({ "animateFidget(${VPointF.fromLong(long1)})" }) { long1 = VPointF(x, y).toLong() }
    }

    companion object {
Loading