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

Commit 9838c829 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Corrects animation for moving ActivityEmbeddings" into main

parents 6bfa0a45 d6986170
Loading
Loading
Loading
Loading
+43 −38
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.wm.shell.desktopmode
package com.android.wm.shell.desktopmode


import android.animation.Animator
import android.animation.Animator
import android.animation.AnimatorSet
import android.animation.ValueAnimator
import android.animation.ValueAnimator
import android.os.IBinder
import android.os.IBinder
import android.view.Choreographer
import android.view.Choreographer
@@ -28,9 +29,7 @@ import com.android.wm.shell.shared.animation.Interpolators
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.transition.Transitions
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.milliseconds


/**
/** Transition handler for moving a window to a different display. */
 * Transition handler for moving a window to a different display.
 */
class DesktopModeMoveToDisplayTransitionHandler(
class DesktopModeMoveToDisplayTransitionHandler(
    private val animationTransaction: SurfaceControl.Transaction
    private val animationTransaction: SurfaceControl.Transaction
) : Transitions.TransitionHandler {
) : Transitions.TransitionHandler {
@@ -47,30 +46,37 @@ class DesktopModeMoveToDisplayTransitionHandler(
        finishTransaction: SurfaceControl.Transaction,
        finishTransaction: SurfaceControl.Transaction,
        finishCallback: Transitions.TransitionFinishCallback,
        finishCallback: Transitions.TransitionFinishCallback,
    ): Boolean {
    ): Boolean {
        val change = info.changes.find { it.startDisplayId != it.endDisplayId } ?: return false
        val changes = info.changes.filter { it.startDisplayId != it.endDisplayId }
        ValueAnimator.ofFloat(0f, 1f)
        if (changes.isEmpty()) return false
            .apply {
        for (change in changes) {
            val endBounds = change.endAbsBounds
            // The position should be relative to the parent. For example, in ActivityEmbedding, the
            // leash surface for the embedded Activity is parented to the container.
            val endPosition = change.endRelOffset
            startTransaction
                .setPosition(change.leash, endPosition.x.toFloat(), endPosition.y.toFloat())
                .setWindowCrop(change.leash, endBounds.width(), endBounds.height())
        }
        startTransaction.apply()

        val animator = AnimatorSet()
        animator.playTogether(
            changes.map {
                ValueAnimator.ofFloat(0f, 1f).apply {
                    duration = ANIM_DURATION.inWholeMilliseconds
                    duration = ANIM_DURATION.inWholeMilliseconds
                    interpolator = Interpolators.LINEAR
                    interpolator = Interpolators.LINEAR
                    addUpdateListener { animation ->
                    addUpdateListener { animation ->
                        animationTransaction
                        animationTransaction
                        .setAlpha(change.leash, animation.animatedValue as Float)
                            .setAlpha(it.leash, animation.animatedValue as Float)
                            .setFrameTimeline(Choreographer.getInstance().vsyncId)
                            .setFrameTimeline(Choreographer.getInstance().vsyncId)
                            .apply()
                            .apply()
                    }
                    }
                addListener(
                    object : Animator.AnimatorListener {
                        override fun onAnimationStart(animation: Animator) {
                            val endBounds = change.endAbsBounds
                            startTransaction
                                .setPosition(
                                    change.leash,
                                    endBounds.left.toFloat(),
                                    endBounds.top.toFloat(),
                                )
                                .setWindowCrop(change.leash, endBounds.width(), endBounds.height())
                                .apply()
                }
                }
            }
        )
        animator.addListener(
            object : Animator.AnimatorListener {
                override fun onAnimationStart(animation: Animator) = Unit


                override fun onAnimationEnd(animation: Animator) {
                override fun onAnimationEnd(animation: Animator) {
                    finishTransaction.apply()
                    finishTransaction.apply()
@@ -85,8 +91,7 @@ class DesktopModeMoveToDisplayTransitionHandler(
                override fun onAnimationRepeat(animation: Animator) = Unit
                override fun onAnimationRepeat(animation: Animator) = Unit
            }
            }
        )
        )
            }
        animator.start()
            .start()
        return true
        return true
    }
    }


+83 −2
Original line number Original line Diff line number Diff line
@@ -16,8 +16,10 @@


package com.android.wm.shell.desktopmode
package com.android.wm.shell.desktopmode


import android.graphics.Rect
import android.testing.AndroidTestingRunner
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.testing.TestableLooper.RunWithLooper
import android.view.SurfaceControl
import android.view.WindowManager
import android.view.WindowManager
import android.window.TransitionInfo
import android.window.TransitionInfo
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
@@ -30,6 +32,8 @@ import org.junit.Before
import org.junit.Test
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runner.RunWith
import org.mockito.kotlin.mock
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.verify


@SmallTest
@SmallTest
@RunWithLooper
@RunWithLooper
@@ -55,7 +59,9 @@ class DesktopModeMoveToDisplayTransitionHandlerTest : ShellTestCase() {
                info =
                info =
                    TransitionInfo(WindowManager.TRANSIT_CHANGE, /* flags= */ 0).apply {
                    TransitionInfo(WindowManager.TRANSIT_CHANGE, /* flags= */ 0).apply {
                        addChange(
                        addChange(
                            TransitionInfo.Change(mock(), mock()).apply { setDisplayId(1, 1) }
                            TransitionInfo.Change(mock(), mock()).apply {
                                setDisplayId(/* start= */ 1, /* end= */ 1)
                            }
                        )
                        )
                    },
                    },
                startTransaction = StubTransaction(),
                startTransaction = StubTransaction(),
@@ -74,7 +80,9 @@ class DesktopModeMoveToDisplayTransitionHandlerTest : ShellTestCase() {
                info =
                info =
                    TransitionInfo(WindowManager.TRANSIT_CHANGE, /* flags= */ 0).apply {
                    TransitionInfo(WindowManager.TRANSIT_CHANGE, /* flags= */ 0).apply {
                        addChange(
                        addChange(
                            TransitionInfo.Change(mock(), mock()).apply { setDisplayId(1, 2) }
                            TransitionInfo.Change(mock(), mock()).apply {
                                setDisplayId(/* start= */ 1, /* end= */ 2)
                            }
                        )
                        )
                    },
                    },
                startTransaction = StubTransaction(),
                startTransaction = StubTransaction(),
@@ -84,4 +92,77 @@ class DesktopModeMoveToDisplayTransitionHandlerTest : ShellTestCase() {


        assertTrue("Should animate display change transition", animates)
        assertTrue("Should animate display change transition", animates)
    }
    }

    @Test
    fun startAnimation_movingActivityEmbedding_shouldSetCorrectBounds() {
        val leashLeft = mock<SurfaceControl>()
        val leashRight = mock<SurfaceControl>()
        val leashContainer = mock<SurfaceControl>()
        val startTransaction = spy(StubTransaction())

        handler.startAnimation(
            transition = mock(),
            info =
                TransitionInfo(WindowManager.TRANSIT_CHANGE, /* flags= */ 0).apply {
                    addChange(
                        TransitionInfo.Change(mock(), mock()).apply {
                            flags = TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY
                            leash = leashLeft
                            setDisplayId(/* start= */ 1, /* end= */ 2)
                            setEndAbsBounds(
                                Rect(
                                    /* left= */ 100,
                                    /* top= */ 100,
                                    /* right= */ 500,
                                    /* bottom= */ 700,
                                )
                            )
                            setEndRelOffset(/* left= */ 0, /* top= */ 0)
                        }
                    )
                    addChange(
                        TransitionInfo.Change(mock(), mock()).apply {
                            flags = TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY
                            leash = leashRight
                            setDisplayId(1, 2)
                            setEndAbsBounds(
                                Rect(
                                    /* left= */ 500,
                                    /* top= */ 100,
                                    /* right= */ 900,
                                    /* bottom= */ 700,
                                )
                            )
                            setEndRelOffset(/* left= */ 400, /* top= */ 0)
                        }
                    )
                    addChange(
                        TransitionInfo.Change(mock(), mock()).apply {
                            flags = TransitionInfo.FLAG_TRANSLUCENT
                            leash = leashContainer
                            setDisplayId(/* start= */ 1, /* end= */ 2)
                            setEndAbsBounds(
                                Rect(
                                    /* left= */ 100,
                                    /* top= */ 100,
                                    /* right= */ 900,
                                    /* bottom= */ 700,
                                )
                            )
                            setEndRelOffset(/* left= */ 100, /* top= */ 100)
                        }
                    )
                },
            startTransaction = startTransaction,
            finishTransaction = StubTransaction(),
            finishCallback = mock(),
        )

        verify(startTransaction).setPosition(leashLeft, 0f, 0f)
        verify(startTransaction).setPosition(leashRight, 400f, 0f)
        verify(startTransaction).setPosition(leashContainer, 100f, 100f)
        verify(startTransaction).setWindowCrop(leashLeft, 400, 600)
        verify(startTransaction).setWindowCrop(leashRight, 400, 600)
        verify(startTransaction).setWindowCrop(leashContainer, 800, 600)
    }
}
}