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

Commit 19131a86 authored by Hawkwood's avatar Hawkwood
Browse files

Weakly hold callback reference from OnPredrawListener

Weakly holding the required predraw references prevents leaking the
transition and all captured views if the PredrawListener is not
correctly cleaned up.

Bug: 414596090
Flag: NONE Bugfix
Test: Manually checked clock switch animation in several scenarios
Change-Id: Ibe64caff6648034da2ab9558edabc54d2eb9274a
parent 5e2d6f5c
Loading
Loading
Loading
Loading
+20 −4
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import com.android.systemui.plugins.clocks.ClockViewIds
import com.android.systemui.res.R
import com.android.systemui.shared.R as sharedR
import com.google.android.material.math.MathUtils
import java.lang.ref.WeakReference
import kotlin.math.abs

internal fun View.getRect(): Rect = Rect(this.left, this.top, this.right, this.bottom)
@@ -231,10 +232,7 @@ class ClockSizeTransition(
                // We enforce the animation parameters on the target view every frame using a
                // predraw listener. This is suboptimal but prevents issues with layout passes
                // overwriting the animation for individual frames.
                val predrawCallback = OnPreDrawListener {
                    assignAnimValues("predraw", anim.animatedFraction, log = false)
                    return@OnPreDrawListener true
                }
                val predrawCallback = PredrawAnimationCallback(anim, ::assignAnimValues)

                this@VisibilityBoundsTransition.addListener(
                    object : TransitionListenerAdapter() {
@@ -279,6 +277,24 @@ class ClockSizeTransition(
        }
    }

    private class PredrawAnimationCallback(
        anim: ValueAnimator,
        cb: (String, Float, Int?, Boolean) -> Unit,
    ) : OnPreDrawListener {
        // Holding only WeakReferences prevents leaking the entire transition and all related views
        // in the event that a predraw listener survives the cleanup steps and is still attached to
        // the ViewTreeObserver past the terminiation of the transition.
        private val callback = WeakReference(cb)
        private val animation = WeakReference(anim)

        override fun onPreDraw(): Boolean {
            val cb = callback.get() ?: return true
            val fraction = animation.get()?.animatedFraction ?: 1f
            cb("predraw", fraction, null, false)
            return true
        }
    }

    abstract class ClockFaceTransition(
        config: IntraBlueprintTransition.Config,
        val viewModel: KeyguardClockViewModel,