summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Hawkwood Glazier <jglazier@google.com> 2025-03-08 15:40:41 -0800
committer Android (Google) Code Review <android-gerrit@google.com> 2025-03-08 15:40:41 -0800
commit41f920977d797b196b36eeffaf42aa3aa5c32f18 (patch)
treed82019c5bc4b0835a84ba0478864811013358824
parent601a5e0f8f1d648947b4609b91a0969144f74d68 (diff)
parent0a737d0746cb8780f84ec899767d6135ba7511d4 (diff)
Merge "Normalize TextInterpolator rebase operations" into main
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt19
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt18
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt9
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt48
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt6
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VPoint.kt8
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VRect.kt12
7 files changed, 92 insertions, 28 deletions
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
index 4a39cff388a9..4f01d7fcdb51 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
@@ -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(
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
index 457f45388062..22c5258edb58 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
@@ -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()
}
/**
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index 6e29e6932629..2f819d183bcc 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -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
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
index 2af25fe339a2..da9e26ae3812 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
@@ -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)
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt
index f9ff75d5fdc8..5b67edda73cc 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt
@@ -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 {
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VPoint.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VPoint.kt
index 1fb37ec28835..de62f9c8be74 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VPoint.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VPoint.kt
@@ -56,6 +56,8 @@ value class VPointF(val data: ULong) {
fun toPointF() = PointF(x, y)
+ fun toLong(): Long = data.toLong()
+
fun lengthSq(): Float = x * x + y * y
fun length(): Float = sqrt(lengthSq())
@@ -110,6 +112,8 @@ value class VPointF(val data: ULong) {
companion object {
val ZERO = VPointF(0, 0)
+ fun fromLong(data: Long) = VPointF(data.toULong())
+
fun max(lhs: VPointF, rhs: VPointF) = VPointF(max(lhs.x, rhs.x), max(lhs.y, rhs.y))
fun min(lhs: VPointF, rhs: VPointF) = VPointF(min(lhs.x, rhs.x), min(lhs.y, rhs.y))
@@ -148,6 +152,8 @@ value class VPoint(val data: ULong) {
fun toPoint() = Point(x, y)
+ fun toLong(): Long = data.toLong()
+
fun abs() = VPoint(abs(x), abs(y))
operator fun component1(): Int = x
@@ -191,6 +197,8 @@ value class VPoint(val data: ULong) {
companion object {
val ZERO = VPoint(0, 0)
+ fun fromLong(data: Long) = VPoint(data.toULong())
+
fun max(lhs: VPoint, rhs: VPoint) = VPoint(max(lhs.x, rhs.x), max(lhs.y, rhs.y))
fun min(lhs: VPoint, rhs: VPoint) = VPoint(min(lhs.x, rhs.x), min(lhs.y, rhs.y))
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VRect.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VRect.kt
index 3c1adf22a405..1bd29aa6a073 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VRect.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/VRect.kt
@@ -84,6 +84,10 @@ value class VRectF(val data: ULong) {
val size: VPointF
get() = VPointF(width, height)
+ fun toRectF(): RectF = RectF(left, top, right, bottom)
+
+ fun toLong(): Long = data.toLong()
+
override fun toString() = "($left, $top) -> ($right, $bottom)"
companion object {
@@ -91,6 +95,8 @@ value class VRectF(val data: ULong) {
private fun fromBits(value: Short): Float = Half.toFloat(Half.intBitsToHalf(value.toInt()))
+ fun fromLong(data: Long) = VRectF(data.toULong())
+
fun fromCenter(center: VPointF, size: VPointF): VRectF {
return VRectF(
center.x - size.x / 2,
@@ -162,11 +168,17 @@ value class VRect(val data: ULong) {
val size: VPoint
get() = VPoint(width, height)
+ fun toRect(): Rect = Rect(left, top, right, bottom)
+
+ fun toLong(): Long = data.toLong()
+
override fun toString() = "($left, $top) -> ($right, $bottom)"
companion object {
val ZERO = VRect(0, 0, 0, 0)
+ fun fromLong(data: Long) = VRect(data.toULong())
+
fun fromCenter(center: VPoint, size: VPoint): VRect {
return VRect(
(center.x - size.x / 2).toShort(),