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

Commit 6f879b8a authored by Yein Jo's avatar Yein Jo
Browse files

Extract common render callback interfaces.

Bug: 332897614
Test: MediaControlPanel, LoadingEffectTest
Flag: ACONFIG shaderlib_loading_effect_refactor DEVELOPMENT
Change-Id: I22f737117ee6b1e5b246eda4a3870f2959a34efa
parent 3516a9d7
Loading
Loading
Loading
Loading
+53 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.surfaceeffects

import android.graphics.Paint
import android.graphics.RenderEffect

/**
 * A callback with a [Paint] object that contains shader info, which is triggered every frame while
 * animation is playing. Note that the [Paint] object here is always the same instance.
 *
 * This approach is more performant than other ones because [RenderEffect] forces an intermediate
 * render pass of the View to a texture to feed into it.
 *
 * The usage of this callback is as follows:
 * <pre>{@code
 *     private var paint: Paint? = null
 *     // Override [View.onDraw].
 *     override fun onDraw(canvas: Canvas) {
 *         // RuntimeShader requires hardwareAcceleration.
 *         if (!canvas.isHardwareAccelerated) return
 *
 *         paint?.let { canvas.drawPaint(it) }
 *     }
 *
 *     // Given that this is called [PaintDrawCallback.onDraw]
 *     fun draw(paint: Paint) {
 *         this.paint = paint
 *
 *         // Must call invalidate to trigger View#onDraw
 *         invalidate()
 *     }
 * }</pre>
 *
 * Please refer to [RenderEffectDrawCallback] for alternative approach.
 */
interface PaintDrawCallback {
    fun onDraw(paint: Paint)
}
+39 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.surfaceeffects

import android.graphics.RenderEffect

/**
 * A callback with a [RenderEffect] object that contains shader info, which is triggered every frame
 * while animation is playing. Note that the [RenderEffect] instance is different each time to
 * update shader uniforms.
 *
 * The usage of this callback is as follows:
 * <pre>{@code
 *     private val xEffectDrawingCallback = RenderEffectDrawCallback() {
 *         val myOtherRenderEffect = createOtherRenderEffect()
 *         val chainEffect = RenderEffect.createChainEffect(renderEffect, myOtherRenderEffect)
 *         myView.setRenderEffect(chainEffect)
 *     }
 *
 *     private val xEffect = XEffect(config, xEffectDrawingCallback)
 * }</pre>
 */
interface RenderEffectDrawCallback {
    fun onDraw(renderEffect: RenderEffect)
}
+24 −43
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import android.animation.ValueAnimator
import android.graphics.Paint
import android.graphics.RenderEffect
import android.view.View
import com.android.systemui.surfaceeffects.PaintDrawCallback
import com.android.systemui.surfaceeffects.RenderEffectDrawCallback
import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseAnimationConfig
import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseShader

@@ -334,14 +336,13 @@ private constructor(
        )
    }

    companion object {
    /**
     * States of the loading effect animation.
     *
     * <p>The state is designed to be follow the order below: [AnimationState.EASE_IN],
         * [AnimationState.MAIN], [AnimationState.EASE_OUT]. Note that ease in and out don't
         * necessarily mean the acceleration and deceleration in the animation curve. They simply
         * mean each stage of the animation. (i.e. Intro, core, and rest)
     * [AnimationState.MAIN], [AnimationState.EASE_OUT]. Note that ease in and out don't necessarily
     * mean the acceleration and deceleration in the animation curve. They simply mean each stage of
     * the animation. (i.e. Intro, core, and rest)
     */
    enum class AnimationState {
        EASE_IN,
@@ -350,25 +351,6 @@ private constructor(
        NOT_PLAYING
    }

        /** Client must implement one of the draw callbacks. */
        interface PaintDrawCallback {
            /**
             * A callback with a [Paint] object that contains shader info, which is triggered every
             * frame while animation is playing. Note that the [Paint] object here is always the
             * same instance.
             */
            fun onDraw(loadingPaint: Paint)
        }

        interface RenderEffectDrawCallback {
            /**
             * A callback with a [RenderEffect] object that contains shader info, which is triggered
             * every frame while animation is playing. Note that the [RenderEffect] instance is
             * different each time to update shader uniforms.
             */
            fun onDraw(loadingRenderEffect: RenderEffect)
        }

    /** Optional callback that is triggered when the animation state changes. */
    interface AnimationStateChangedCallback {
        /**
@@ -378,8 +360,7 @@ private constructor(
        fun onStateChanged(oldState: AnimationState, newState: AnimationState) {}
    }

    private companion object {
        private const val MS_TO_SEC = 0.001f

        private val TAG = LoadingEffect::class.java.simpleName
    }
}
+8 −7
Original line number Diff line number Diff line
@@ -118,8 +118,9 @@ import com.android.systemui.res.R;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.surfaceeffects.PaintDrawCallback;
import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect;
import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState;
import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.AnimationState;
import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffectView;
import com.android.systemui.surfaceeffects.ripple.MultiRippleController;
import com.android.systemui.surfaceeffects.ripple.MultiRippleView;
@@ -264,15 +265,15 @@ public class MediaControlPanel {
    private boolean mWasPlaying = false;
    private boolean mButtonClicked = false;

    private final LoadingEffect.Companion.PaintDrawCallback mNoiseDrawCallback =
            new LoadingEffect.Companion.PaintDrawCallback() {
    private final PaintDrawCallback mNoiseDrawCallback =
            new PaintDrawCallback() {
                @Override
                public void onDraw(@NonNull Paint loadingPaint) {
                    mMediaViewHolder.getLoadingEffectView().draw(loadingPaint);
                public void onDraw(@NonNull Paint paint) {
                    mMediaViewHolder.getLoadingEffectView().draw(paint);
                }
            };
    private final LoadingEffect.Companion.AnimationStateChangedCallback mStateChangedCallback =
            new LoadingEffect.Companion.AnimationStateChangedCallback() {
    private final LoadingEffect.AnimationStateChangedCallback mStateChangedCallback =
            new LoadingEffect.AnimationStateChangedCallback() {
                @Override
                public void onStateChanged(@NonNull AnimationState oldState,
                        @NonNull AnimationState newState) {
+51 −29
Original line number Diff line number Diff line
@@ -23,14 +23,8 @@ import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.systemui.animation.AnimatorTestRule
import com.android.systemui.model.SysUiStateTest
import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState
import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState.EASE_IN
import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState.EASE_OUT
import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState.MAIN
import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationState.NOT_PLAYING
import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.AnimationStateChangedCallback
import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.PaintDrawCallback
import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect.Companion.RenderEffectDrawCallback
import com.android.systemui.surfaceeffects.PaintDrawCallback
import com.android.systemui.surfaceeffects.RenderEffectDrawCallback
import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseAnimationConfig
import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseShader
import com.google.common.truth.Truth.assertThat
@@ -50,8 +44,8 @@ class LoadingEffectTest : SysUiStateTest() {
        var paintFromCallback: Paint? = null
        val drawCallback =
            object : PaintDrawCallback {
                override fun onDraw(loadingPaint: Paint) {
                    paintFromCallback = loadingPaint
                override fun onDraw(paint: Paint) {
                    paintFromCallback = paint
                }
            }
        val loadingEffect =
@@ -75,8 +69,8 @@ class LoadingEffectTest : SysUiStateTest() {
        var renderEffectFromCallback: RenderEffect? = null
        val drawCallback =
            object : RenderEffectDrawCallback {
                override fun onDraw(loadingRenderEffect: RenderEffect) {
                    renderEffectFromCallback = loadingRenderEffect
                override fun onDraw(renderEffect: RenderEffect) {
                    renderEffectFromCallback = renderEffect
                }
            }
        val loadingEffect =
@@ -98,16 +92,19 @@ class LoadingEffectTest : SysUiStateTest() {
    @Test
    fun play_animationStateChangesInOrder() {
        val config = TurbulenceNoiseAnimationConfig()
        val states = mutableListOf(NOT_PLAYING)
        val states = mutableListOf(LoadingEffect.AnimationState.NOT_PLAYING)
        val stateChangedCallback =
            object : AnimationStateChangedCallback {
                override fun onStateChanged(oldState: AnimationState, newState: AnimationState) {
            object : LoadingEffect.AnimationStateChangedCallback {
                override fun onStateChanged(
                    oldState: LoadingEffect.AnimationState,
                    newState: LoadingEffect.AnimationState
                ) {
                    states.add(newState)
                }
            }
        val drawCallback =
            object : PaintDrawCallback {
                override fun onDraw(loadingPaint: Paint) {}
                override fun onDraw(paint: Paint) {}
            }
        val loadingEffect =
            LoadingEffect(
@@ -125,7 +122,14 @@ class LoadingEffectTest : SysUiStateTest() {
        animatorTestRule.advanceTimeBy(config.easeOutDuration.toLong())
        animatorTestRule.advanceTimeBy(500)

        assertThat(states).containsExactly(NOT_PLAYING, EASE_IN, MAIN, EASE_OUT, NOT_PLAYING)
        assertThat(states)
            .containsExactly(
                LoadingEffect.AnimationState.NOT_PLAYING,
                LoadingEffect.AnimationState.EASE_IN,
                LoadingEffect.AnimationState.MAIN,
                LoadingEffect.AnimationState.EASE_OUT,
                LoadingEffect.AnimationState.NOT_PLAYING
            )
    }

    @Test
@@ -133,16 +137,22 @@ class LoadingEffectTest : SysUiStateTest() {
        val config = TurbulenceNoiseAnimationConfig()
        var numPlay = 0
        val stateChangedCallback =
            object : AnimationStateChangedCallback {
                override fun onStateChanged(oldState: AnimationState, newState: AnimationState) {
                    if (oldState == NOT_PLAYING && newState == EASE_IN) {
            object : LoadingEffect.AnimationStateChangedCallback {
                override fun onStateChanged(
                    oldState: LoadingEffect.AnimationState,
                    newState: LoadingEffect.AnimationState
                ) {
                    if (
                        oldState == LoadingEffect.AnimationState.NOT_PLAYING &&
                            newState == LoadingEffect.AnimationState.EASE_IN
                    ) {
                        numPlay++
                    }
                }
            }
        val drawCallback =
            object : PaintDrawCallback {
                override fun onDraw(loadingPaint: Paint) {}
                override fun onDraw(paint: Paint) {}
            }
        val loadingEffect =
            LoadingEffect(
@@ -172,9 +182,15 @@ class LoadingEffectTest : SysUiStateTest() {
            }
        var isFinished = false
        val stateChangedCallback =
            object : AnimationStateChangedCallback {
                override fun onStateChanged(oldState: AnimationState, newState: AnimationState) {
                    if (oldState == EASE_OUT && newState == NOT_PLAYING) {
            object : LoadingEffect.AnimationStateChangedCallback {
                override fun onStateChanged(
                    oldState: LoadingEffect.AnimationState,
                    newState: LoadingEffect.AnimationState
                ) {
                    if (
                        oldState == LoadingEffect.AnimationState.EASE_OUT &&
                            newState == LoadingEffect.AnimationState.NOT_PLAYING
                    ) {
                        isFinished = true
                    }
                }
@@ -205,13 +221,19 @@ class LoadingEffectTest : SysUiStateTest() {
        val config = TurbulenceNoiseAnimationConfig(maxDuration = 1000f)
        val drawCallback =
            object : PaintDrawCallback {
                override fun onDraw(loadingPaint: Paint) {}
                override fun onDraw(paint: Paint) {}
            }
        var isFinished = false
        val stateChangedCallback =
            object : AnimationStateChangedCallback {
                override fun onStateChanged(oldState: AnimationState, newState: AnimationState) {
                    if (oldState == MAIN && newState == NOT_PLAYING) {
            object : LoadingEffect.AnimationStateChangedCallback {
                override fun onStateChanged(
                    oldState: LoadingEffect.AnimationState,
                    newState: LoadingEffect.AnimationState
                ) {
                    if (
                        oldState == LoadingEffect.AnimationState.MAIN &&
                            newState == LoadingEffect.AnimationState.NOT_PLAYING
                    ) {
                        isFinished = true
                    }
                }
@@ -242,7 +264,7 @@ class LoadingEffectTest : SysUiStateTest() {
            )
        val drawCallback =
            object : PaintDrawCallback {
                override fun onDraw(loadingPaint: Paint) {}
                override fun onDraw(paint: Paint) {}
            }
        val loadingEffect =
            LoadingEffect(