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

Commit 3802103d authored by Luca Zuccarini's avatar Luca Zuccarini Committed by Android (Google) Code Review
Browse files

Merge "A few fixes for animation takeovers." into main

parents faa70d2a e62bbe81
Loading
Loading
Loading
Loading
+12 −24
Original line number Diff line number Diff line
@@ -867,6 +867,9 @@ constructor(
                    ) {
                        // Raise closing task to "above" layer so it isn't covered.
                        t.setLayer(target.leash, aboveLayers - i)
                    } else if (TransitionUtil.isOpeningType(change.mode)) {
                        // Put into the "below" layer space.
                        t.setLayer(target.leash, belowLayers - i)
                    }
                } else if (TransitionInfo.isIndependent(change, info)) {
                    // Root tasks
@@ -1147,7 +1150,7 @@ constructor(
                // If a [controller.windowAnimatorState] exists, treat this like a takeover.
                takeOverAnimationInternal(
                    window,
                    startWindowStates = null,
                    startWindowState = null,
                    startTransaction = null,
                    callback,
                )
@@ -1162,22 +1165,23 @@ constructor(
            callback: IRemoteAnimationFinishedCallback?,
        ) {
            val window = setUpAnimation(apps, callback) ?: return
            takeOverAnimationInternal(window, startWindowStates, startTransaction, callback)
            val startWindowState = startWindowStates[apps!!.indexOf(window)]
            takeOverAnimationInternal(window, startWindowState, startTransaction, callback)
        }

        private fun takeOverAnimationInternal(
            window: RemoteAnimationTarget,
            startWindowStates: Array<WindowAnimationState>?,
            startWindowState: WindowAnimationState?,
            startTransaction: SurfaceControl.Transaction?,
            callback: IRemoteAnimationFinishedCallback?,
        ) {
            val useSpring =
                !controller.isLaunching && startWindowStates != null && startTransaction != null
                !controller.isLaunching && startWindowState != null && startTransaction != null
            startAnimation(
                window,
                navigationBar = null,
                useSpring,
                startWindowStates,
                startWindowState,
                startTransaction,
                callback,
            )
@@ -1287,7 +1291,7 @@ constructor(
            window: RemoteAnimationTarget,
            navigationBar: RemoteAnimationTarget? = null,
            useSpring: Boolean = false,
            startingWindowStates: Array<WindowAnimationState>? = null,
            startingWindowState: WindowAnimationState? = null,
            startTransaction: SurfaceControl.Transaction? = null,
            iCallback: IRemoteAnimationFinishedCallback? = null,
        ) {
@@ -1333,6 +1337,7 @@ constructor(

            val isExpandingFullyAbove =
                transitionAnimator.isExpandingFullyAbove(controller.transitionContainer, endState)
            val windowState = startingWindowState ?: controller.windowAnimatorState

            // We animate the opening window and delegate the view expansion to [this.controller].
            val delegate = this.controller
@@ -1355,18 +1360,6 @@ constructor(
                                }
                        }

                        // The states are sorted matching the changes inside the transition info.
                        // Using this info, the RemoteAnimationTargets are created, with their
                        // prefixOrderIndex fields in reverse order to that of changes. To extract
                        // the right state, we need to invert again.
                        val windowState =
                            if (startingWindowStates != null) {
                                startingWindowStates[
                                    startingWindowStates.size - window.prefixOrderIndex]
                            } else {
                                controller.windowAnimatorState
                            }

                        // TODO(b/323863002): use the timestamp and velocity to update the initial
                        //   position.
                        val bounds = windowState?.bounds
@@ -1455,12 +1448,6 @@ constructor(
                        delegate.onTransitionAnimationProgress(state, progress, linearProgress)
                    }
                }
            val windowState =
                if (startingWindowStates != null) {
                    startingWindowStates[startingWindowStates.size - window.prefixOrderIndex]
                } else {
                    controller.windowAnimatorState
                }
            val velocityPxPerS =
                if (longLivedReturnAnimationsEnabled() && windowState?.velocityPxPerMs != null) {
                    val xVelocityPxPerS = windowState.velocityPxPerMs.x * 1000
@@ -1479,6 +1466,7 @@ constructor(
                    fadeWindowBackgroundLayer = !controller.isBelowAnimatingWindow,
                    drawHole = !controller.isBelowAnimatingWindow,
                    startVelocity = velocityPxPerS,
                    startFrameTime = windowState?.timestamp ?: -1,
                )
        }

+48 −2
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@ import android.graphics.drawable.GradientDrawable
import android.util.FloatProperty
import android.util.Log
import android.util.MathUtils
import android.util.TimeUtils
import android.view.Choreographer
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroupOverlay
@@ -366,6 +368,7 @@ class TransitionAnimator(
        @get:VisibleForTesting val springY: SpringAnimation,
        @get:VisibleForTesting val springScale: SpringAnimation,
        private val springState: SpringState,
        private val startFrameTime: Long,
        private val onAnimationStart: Runnable,
    ) : Animation {
        @get:VisibleForTesting
@@ -374,6 +377,42 @@ class TransitionAnimator(

        override fun start() {
            onAnimationStart.run()

            // If no start frame time is provided, we start the springs normally.
            if (startFrameTime < 0) {
                startSprings()
                return
            }

            // This function is not guaranteed to be called inside a frame. We try to access the
            // frame time immediately, but if we're not inside a frame this will throw an exception.
            // We must then post a callback to be run at the beginning of the next frame.
            try {
                initAndStartSprings(Choreographer.getInstance().frameTime)
            } catch (_: IllegalStateException) {
                Choreographer.getInstance().postFrameCallback { frameTimeNanos ->
                    initAndStartSprings(frameTimeNanos / TimeUtils.NANOS_PER_MS)
                }
            }
        }

        private fun initAndStartSprings(frameTime: Long) {
            // Initialize the spring as if it had started at the time that its start state
            // was created.
            springX.doAnimationFrame(startFrameTime)
            springY.doAnimationFrame(startFrameTime)
            springScale.doAnimationFrame(startFrameTime)
            // Move the spring time forward to the current frame, so it updates its internal state
            // following the initial momentum over the elapsed time.
            springX.doAnimationFrame(frameTime)
            springY.doAnimationFrame(frameTime)
            springScale.doAnimationFrame(frameTime)
            // Actually start the spring. We do this after the previous calls because the framework
            // doesn't like it when you call doAnimationFrame() after start() with an earlier time.
            startSprings()
        }

        private fun startSprings() {
            springX.start()
            springY.start()
            springScale.start()
@@ -471,7 +510,9 @@ class TransitionAnimator(
     * is true.
     *
     * If [startVelocity] (expressed in pixels per second) is not null, a multi-spring animation
     * using it for the initial momentum will be used instead of the default interpolators.
     * using it for the initial momentum will be used instead of the default interpolators. In this
     * case, [startFrameTime] (if non-negative) represents the frame time at which the springs
     * should be started.
     */
    fun startAnimation(
        controller: Controller,
@@ -480,6 +521,7 @@ class TransitionAnimator(
        fadeWindowBackgroundLayer: Boolean = true,
        drawHole: Boolean = false,
        startVelocity: PointF? = null,
        startFrameTime: Long = -1,
    ): Animation {
        if (!controller.isLaunching) assertReturnAnimations()
        if (startVelocity != null) assertLongLivedReturnAnimations()
@@ -502,6 +544,7 @@ class TransitionAnimator(
                fadeWindowBackgroundLayer,
                drawHole,
                startVelocity,
                startFrameTime,
            )
            .apply { start() }
    }
@@ -515,6 +558,7 @@ class TransitionAnimator(
        fadeWindowBackgroundLayer: Boolean = true,
        drawHole: Boolean = false,
        startVelocity: PointF? = null,
        startFrameTime: Long = -1,
    ): Animation {
        val transitionContainer = controller.transitionContainer
        val transitionContainerOverlay = transitionContainer.overlay
@@ -537,6 +581,7 @@ class TransitionAnimator(
                startState,
                endState,
                startVelocity,
                startFrameTime,
                windowBackgroundLayer,
                transitionContainer,
                transitionContainerOverlay,
@@ -722,6 +767,7 @@ class TransitionAnimator(
        startState: State,
        endState: State,
        startVelocity: PointF,
        startFrameTime: Long,
        windowBackgroundLayer: GradientDrawable,
        transitionContainer: View,
        transitionContainerOverlay: ViewGroupOverlay,
@@ -912,7 +958,7 @@ class TransitionAnimator(
                    }
                }

        return MultiSpringAnimation(springX, springY, springScale, springState) {
        return MultiSpringAnimation(springX, springY, springScale, springState, startFrameTime) {
            onAnimationStart(
                controller,
                isExpandingFullyAbove,