diff options
3 files changed, 35 insertions, 172 deletions
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieEffect.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieEffect.kt index c08afd3e1bda..0cb01fd1e0b0 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieEffect.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieEffect.kt @@ -44,31 +44,42 @@ class GlowPieEffect( fun play() { if (mainAnimator.isRunning) return - baseGlow.resetProgress() - firstGlowPie.resetProgress() - secondGlowPie.resetProgress() - mainAnimator.addUpdateListener { updateListener -> val time = updateListener.currentPlayTime.toFloat() % mainAnimator.duration - // Remap each glow pie progress. - baseGlow.updateProgress(time) - firstGlowPie.updateProgress(time) - secondGlowPie.updateProgress(time) + // TODO(b/335315940): Extract the timestamps to config. + val progress1 = MathUtils.constrainedMap(0f, 1f, 250f, 2500f, time) + val progress2 = MathUtils.constrainedMap(0f, 1f, 350f, 2600f, time) // TODO(b/335315940): Consider passing in 2D Matrix. - glowPieShader.setAngles(baseGlow.angle(), firstGlowPie.angle(), secondGlowPie.angle()) + val angle0 = 0f // No rotation for the base. + // Negate the angle since we want clock-wise rotation. + val angle1 = + -(MathUtils.constrainedMap(-PI / 2f, 4f * PI, 0f, 1f, progress1) + progress1 * PI) + val angle2 = + -(MathUtils.constrainedMap(-PI / 2f, 3f * PI, 0f, 1f, progress2) + progress2 * PI) + glowPieShader.setAngle(angle0, angle1, angle2) + val bottomThreshold0 = 0f + val topThreshold0 = 0f + + val bottomThreshold1 = MathUtils.lerp(1f, -FEATHER, progress1) + val topThreshold1 = MathUtils.lerp(1f + FEATHER, 0f, progress1) + + val bottomThreshold2 = MathUtils.lerp(1f, -FEATHER, progress2) + val topThreshold2 = MathUtils.lerp(1f + FEATHER, 0f, progress2) + glowPieShader.setBottomAngleThresholds( - baseGlow.bottomThreshold(), - firstGlowPie.bottomThreshold(), - secondGlowPie.bottomThreshold() + bottomThreshold0, + bottomThreshold1, + bottomThreshold2 ) - glowPieShader.setTopAngleThresholds( - baseGlow.topThreshold(), - firstGlowPie.topThreshold(), - secondGlowPie.topThreshold() - ) - glowPieShader.setAlphas(baseGlow.alpha(), firstGlowPie.alpha(), secondGlowPie.alpha()) + glowPieShader.setTopAngleThresholds(topThreshold0, topThreshold1, topThreshold2) + + // Remap timestamps (in MS) to alpha [0, 1]. + val alpha0 = MathUtils.constrainedMap(0f, 1f, 2250f, 2950f, time) + val alpha1 = MathUtils.constrainedMap(1f, 0f, 2500f, 2750f, time) + val alpha2 = MathUtils.constrainedMap(1f, 0f, 2600f, 2850f, time) + glowPieShader.setAlphas(alpha0, alpha1, alpha2) // Finally trigger the draw callback. renderEffectDrawCallback.onDraw( @@ -87,123 +98,10 @@ class GlowPieEffect( mainAnimator.cancel() } - companion object { - @VisibleForTesting const val PI = Math.PI.toFloat() - @VisibleForTesting const val FEATHER = 0.3f - @VisibleForTesting const val DURATION_MS = 3000L - - private val baseGlow = BaseGlow() - private val firstGlowPie = FirstGlowPie() - private val secondGlowPie = SecondGlowPie() - } - - /** Contains animation parameters for each layer of glow pie. */ - interface GlowPie { - /** - * The start & end timestamps of the animation. Must be smaller than or equal to the full - * [DURATION_MS]. - */ - val startMs: Float - val endMs: Float - /** - * Start & end angles in radian. This determines how many cycles you want to rotate. e.g. - * startAngle = 0f endAngle = 4f * PI, will give you the 2 cycles. - */ - val startAngle: Float - val endAngle: Float - /** - * Start & end timestamps of the fade out duration. You may want to override [alpha] if you - * want to make it fade in. See [BaseGlow]. - */ - val alphaFadeStartMs: Float - val alphaFadeEndMs: Float - - /** Below two values are expected to be updated through [updateProgress]. */ - /** Normalized progress. */ - var progress: Float - /** current time of the animation in ms. */ - var time: Float - - // Must be called before retrieving angle, bottom & top thresholds, and alpha. - // Otherwise the values would be stale. - fun updateProgress(time: Float) { - progress = MathUtils.constrainedMap(0f, 1f, startMs, endMs, time) - this.time = time - } - - fun resetProgress() { - progress = 0f - time = 0f - } - - fun angle(): Float { - // Negate the angle since we want clock-wise rotation. - val angle = - MathUtils.constrainedMap(startAngle, endAngle, 0f, 1f, progress) + progress * PI - return -angle - } - - fun bottomThreshold(): Float { - return MathUtils.lerp(1f, -FEATHER, progress) - } - - fun topThreshold(): Float { - return MathUtils.lerp(1f + FEATHER, 0f, progress) - } - - // By default, it fades "out". - fun alpha(): Float { - // Remap timestamps (in MS) to alpha [0, 1]. - return MathUtils.constrainedMap(1f, 0f, alphaFadeStartMs, alphaFadeEndMs, time) - } - } - - data class BaseGlow( - override val startMs: Float = 0f, - override val endMs: Float = 0f, - override val startAngle: Float = 0f, - override val endAngle: Float = 0f, - override val alphaFadeStartMs: Float = 2250f, - override val alphaFadeEndMs: Float = 2950f, - ) : GlowPie { - - override var progress: Float = 1f - override var time: Float = 0f - override fun updateProgress(time: Float) {} - - override fun resetProgress() {} - - override fun angle(): Float = 0f - - override fun bottomThreshold(): Float = 0f - - override fun topThreshold(): Float = 0f - - // Base glow fade "in" (i.e. reveals). - override fun alpha(): Float { - return MathUtils.constrainedMap(0f, 1f, alphaFadeStartMs, alphaFadeEndMs, time) - } + private companion object { + private const val PI = Math.PI.toFloat() + private const val FEATHER = 0.3f + // This indicates a single loop of the animation. + private const val DURATION_MS = 3000L } - - data class FirstGlowPie( - override val startMs: Float = 250f, - override val endMs: Float = 2500f, - override val startAngle: Float = -PI / 2f, - override val endAngle: Float = 4f * PI, - override val alphaFadeStartMs: Float = 2500f, - override val alphaFadeEndMs: Float = 2750f, - override var progress: Float = 0f, - override var time: Float = 0f - ) : GlowPie - - data class SecondGlowPie( - override val startMs: Float = 350f, - override val endMs: Float = 2600f, - override val startAngle: Float = -PI / 2f, - override val endAngle: Float = 3f * PI, - override val alphaFadeStartMs: Float = 2600f, - override val alphaFadeEndMs: Float = 2850f, - override var progress: Float = 0f, - override var time: Float = 0f - ) : GlowPie } diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieShader.kt index 2dbc0b5e24aa..cbb781fa4950 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieShader.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieShader.kt @@ -199,7 +199,7 @@ class GlowPieShader : RuntimeShader(GLOW_PIE_SHADER_COMP) { setColorUniform("in_colors2", colors[2]) } - fun setAngles(vararg angles: Float) { + fun setAngle(vararg angles: Float) { if (angles.size != NUM_PIE) { Log.wtf(TAG, "The number of angles must be $NUM_PIE") return diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieEffectTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieEffectTest.kt index 8105cc58b58e..792d65c0d556 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieEffectTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/gloweffect/GlowPieEffectTest.kt @@ -91,39 +91,4 @@ class GlowPieEffectTest : SysUiStateTest() { assertThat(glowPieEffect.mainAnimator.isRunning).isFalse() } - - @Test - fun glowPie_progress_computesProgressCorrectly() { - val myGlowPieConfig = - object : GlowPieEffect.GlowPie { - override val startMs: Float = 0f - override val endMs: Float = GlowPieEffect.DURATION_MS.toFloat() - override val startAngle: Float = 0f - override val endAngle: Float = 6f * GlowPieEffect.PI - override val alphaFadeStartMs: Float = 0f - override val alphaFadeEndMs: Float = GlowPieEffect.DURATION_MS.toFloat() - override var progress: Float = 0f - override var time: Float = 0f - } - - val playTime = GlowPieEffect.DURATION_MS.toFloat() * 0.5f - val tolerance = 1e-4f - myGlowPieConfig.updateProgress(playTime) - - assertThat(myGlowPieConfig.time).isWithin(tolerance).of(playTime) - assertThat(myGlowPieConfig.progress).isWithin(tolerance).of(0.5f) - assertThat(myGlowPieConfig.angle()).isWithin(tolerance).of(-3.5f * GlowPieEffect.PI) - assertThat(myGlowPieConfig.bottomThreshold()) - .isWithin(tolerance) - .of((1f - GlowPieEffect.FEATHER) * 0.5f) - assertThat(myGlowPieConfig.topThreshold()) - .isWithin(tolerance) - .of((1f + GlowPieEffect.FEATHER) * 0.5f) - assertThat(myGlowPieConfig.alpha()).isWithin(tolerance).of(0.5f) - - myGlowPieConfig.resetProgress() - - assertThat(myGlowPieConfig.time).isEqualTo(0f) - assertThat(myGlowPieConfig.progress).isEqualTo(0f) - } } |