Add return animation functionality to TransitionAnimator.

Bug: 323863002
Flag: ACONFIG com.android.systemui.shared.return_animation_framework_library DISABLED
Test: Manually tested existing use cases with the flag on and off (same
behavior), added unit test

Change-Id: I391c6ae784871e17262649d0f17343ac87b6a6d4
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index f911269..5d1e2c3 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -233,6 +233,9 @@
     resource_dirs: [
         "tests/res",
     ],
+    asset_dirs: [
+        "tests/goldens",
+    ],
     static_libs: [
         "SystemUI-res",
         "WifiTrackerLib",
@@ -334,6 +337,8 @@
         "androidx.test.ext.junit",
         "androidx.test.ext.truth",
         "kotlin-test",
+        "platform-screenshot-diff-core",
+        "PlatformMotionTesting",
         "SystemUICustomizationTestUtils",
         "androidx.compose.runtime_runtime",
     ],
diff --git a/packages/SystemUI/animation/Android.bp b/packages/SystemUI/animation/Android.bp
index 2268d16..dce2c65 100644
--- a/packages/SystemUI/animation/Android.bp
+++ b/packages/SystemUI/animation/Android.bp
@@ -48,6 +48,7 @@
         "SystemUIShaderLib",
         "WindowManager-Shell-shared",
         "animationlib",
+        "com_android_systemui_shared_flags_lib",
     ],
 
     manifest: "AndroidManifest.xml",
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
index ea1cb34..9ce30fd 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
@@ -790,7 +790,7 @@
                     controller,
                     endState,
                     windowBackgroundColor,
-                    fadeOutWindowBackgroundLayer = !controller.isBelowAnimatingWindow,
+                    fadeWindowBackgroundLayer = !controller.isBelowAnimatingWindow,
                     drawHole = !controller.isBelowAnimatingWindow,
                 )
         }
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogTransitionAnimator.kt
index dbdf970..20087c4 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogTransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogTransitionAnimator.kt
@@ -917,6 +917,12 @@
                         endController.transitionContainer = value
                     }
 
+                // We tell TransitionController that this is always a launch, and handle the launch
+                // vs return logic internally.
+                // TODO(b/323863002): maybe move the launch vs return logic out of this class and
+                //     delegate it to TransitionController?
+                override val isLaunching: Boolean = true
+
                 override fun createAnimatorState(): TransitionAnimator.State {
                     return startController.createAnimatorState()
                 }
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
index 3f57f88..9ad0fc5 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt
@@ -64,6 +64,7 @@
     private var interactionJankMonitor: InteractionJankMonitor =
         InteractionJankMonitor.getInstance(),
 ) : ActivityTransitionAnimator.Controller {
+    override val isLaunching: Boolean = true
 
     /** The container to which we will add the ghost view and expanding background. */
     override var transitionContainer = ghostedView.rootView as ViewGroup
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
index 5e4276c..9bf6b34 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
@@ -28,7 +28,9 @@
 import android.view.View
 import android.view.ViewGroup
 import android.view.animation.Interpolator
+import androidx.annotation.VisibleForTesting
 import com.android.app.animation.Interpolators.LINEAR
+import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary
 import kotlin.math.roundToInt
 
 private const val TAG = "TransitionAnimator"
@@ -70,13 +72,14 @@
     interface Controller {
         /**
          * The container in which the view that started the animation will be animating together
-         * with the opening window.
+         * with the opening or closing window.
          *
          * This will be used to:
          * - Get the associated [Context].
-         * - Compute whether we are expanding fully above the transition container.
-         * - Get to overlay to which we initially put the window background layer, until the opening
-         *   window is made visible (see [openingWindowSyncView]).
+         * - Compute whether we are expanding to or contracting from fully above the transition
+         *   container.
+         * - Get the overlay into which we put the window background layer, while the animating
+         *   window is not visible (see [openingWindowSyncView]).
          *
          * This container can be changed to force this [Controller] to animate the expanding view
          * inside a different location, for instance to ensure correct layering during the
@@ -84,12 +87,17 @@
          */
         var transitionContainer: ViewGroup
 
+        /** Whether the animation being controlled is a launch or a return. */
+        val isLaunching: Boolean
+
         /**
-         * The [View] with which the opening app window should be synchronized with once it starts
-         * to be visible.
+         * If [isLaunching], the [View] with which the opening app window should be synchronized
+         * once it starts to be visible. Otherwise, the [View] with which the closing app window
+         * should be synchronized until it stops being visible.
          *
          * We will also move the window background layer to this view's overlay once the opening
-         * window is visible.
+         * window is visible (if [isLaunching]), or from this view's overlay once the closing window
+         * stop being visible (if ![isLaunching]).
          *
          * If null, this will default to [transitionContainer].
          */
@@ -203,17 +211,56 @@
      * layer with [windowBackgroundColor] will fade in then (optionally) fade out above the
      * expanding view, and should be the same background color as the opening (or closing) window.
      *
-     * If [fadeOutWindowBackgroundLayer] is true, then this intermediary layer will fade out during
-     * the second half of the animation, and will have SRC blending mode (ultimately punching a hole
-     * in the [transition container][Controller.transitionContainer]) iff [drawHole] is true.
+     * If [fadeWindowBackgroundLayer] is true, then this intermediary layer will fade out during the
+     * second half of the animation (if [Controller.isLaunching] or fade in during the first half of
+     * the animation (if ![Controller.isLaunching]), and will have SRC blending mode (ultimately
+     * punching a hole in the [transition container][Controller.transitionContainer]) iff [drawHole]
+     * is true.
      */
     fun startAnimation(
         controller: Controller,
         endState: State,
         windowBackgroundColor: Int,
-        fadeOutWindowBackgroundLayer: Boolean = true,
+        fadeWindowBackgroundLayer: Boolean = true,
         drawHole: Boolean = false,
     ): Animation {
+        if (!controller.isLaunching) checkReturnAnimationFrameworkFlag()
+
+        // We add an extra layer with the same color as the dialog/app splash screen background
+        // color, which is usually the same color of the app background. We first fade in this layer
+        // to hide the expanding view, then we fade it out with SRC mode to draw a hole in the
+        // transition container and reveal the opening window.
+        val windowBackgroundLayer =
+            GradientDrawable().apply {
+                setColor(windowBackgroundColor)
+                alpha = 0
+            }
+
+        val animator =
+            createAnimator(
+                controller,
+                endState,
+                windowBackgroundLayer,
+                fadeWindowBackgroundLayer,
+                drawHole
+            )
+        animator.start()
+
+        return object : Animation {
+            override fun cancel() {
+                animator.cancel()
+            }
+        }
+    }
+
+    @VisibleForTesting
+    fun createAnimator(
+        controller: Controller,
+        endState: State,
+        windowBackgroundLayer: GradientDrawable,
+        fadeWindowBackgroundLayer: Boolean = true,
+        drawHole: Boolean = false
+    ): ValueAnimator {
         val state = controller.createAnimatorState()
 
         // Start state.
@@ -255,31 +302,24 @@
         val transitionContainer = controller.transitionContainer
         val isExpandingFullyAbove = isExpandingFullyAbove(transitionContainer, endState)
 
-        // We add an extra layer with the same color as the dialog/app splash screen background
-        // color, which is usually the same color of the app background. We first fade in this layer
-        // to hide the expanding view, then we fade it out with SRC mode to draw a hole in the
-        // transition container and reveal the opening window.
-        val windowBackgroundLayer =
-            GradientDrawable().apply {
-                setColor(windowBackgroundColor)
-                alpha = 0
-            }
-
         // Update state.
         val animator = ValueAnimator.ofFloat(0f, 1f)
         animator.duration = timings.totalDuration
         animator.interpolator = LINEAR
 
         // Whether we should move the [windowBackgroundLayer] into the overlay of
-        // [Controller.openingWindowSyncView] once the opening app window starts to be visible.
+        // [Controller.openingWindowSyncView] once the opening app window starts to be visible, or
+        // from it once the closing app window stops being visible.
+        // This is necessary as a one-off sync so we can avoid syncing at every frame, especially
+        // in complex interactions like launching an activity from a dialog. See
+        // b/214961273#comment2 for more details.
         val openingWindowSyncView = controller.openingWindowSyncView
         val openingWindowSyncViewOverlay = openingWindowSyncView?.overlay
-        val moveBackgroundLayerWhenAppIsVisible =
+        val moveBackgroundLayerWhenAppVisibilityChanges =
             openingWindowSyncView != null &&
                 openingWindowSyncView.viewRootImpl != controller.transitionContainer.viewRootImpl
 
         val transitionContainerOverlay = transitionContainer.overlay
-        var cancelled = false
         var movedBackgroundLayer = false
 
         animator.addListener(
@@ -293,7 +333,11 @@
                     // Add the drawable to the transition container overlay. Overlays always draw
                     // drawables after views, so we know that it will be drawn above any view added
                     // by the controller.
-                    transitionContainerOverlay.add(windowBackgroundLayer)
+                    if (controller.isLaunching || openingWindowSyncViewOverlay == null) {
+                        transitionContainerOverlay.add(windowBackgroundLayer)
+                    } else {
+                        openingWindowSyncViewOverlay.add(windowBackgroundLayer)
+                    }
                 }
 
                 override fun onAnimationEnd(animation: Animator) {
@@ -303,7 +347,7 @@
                     controller.onTransitionAnimationEnd(isExpandingFullyAbove)
                     transitionContainerOverlay.remove(windowBackgroundLayer)
 
-                    if (moveBackgroundLayerWhenAppIsVisible) {
+                    if (moveBackgroundLayerWhenAppVisibilityChanges && controller.isLaunching) {
                         openingWindowSyncViewOverlay?.remove(windowBackgroundLayer)
                     }
                 }
@@ -311,12 +355,6 @@
         )
 
         animator.addUpdateListener { animation ->
-            if (cancelled) {
-                // TODO(b/184121838): Cancel the animator directly instead of just skipping the
-                // update.
-                return@addUpdateListener
-            }
-
             maybeUpdateEndState()
 
             // TODO(b/184121838): Use reverse interpolators to get the same path/arc as the non
@@ -338,20 +376,34 @@
             state.bottomCornerRadius =
                 MathUtils.lerp(startBottomCornerRadius, endBottomCornerRadius, progress)
 
-            // The expanding view can/should be hidden once it is completely covered by the opening
-            // window.
             state.visible =
-                getProgress(
-                    timings,
-                    linearProgress,
-                    timings.contentBeforeFadeOutDelay,
-                    timings.contentBeforeFadeOutDuration
-                ) < 1
+                if (controller.isLaunching) {
+                    // The expanding view can/should be hidden once it is completely covered by the
+                    // opening window.
+                    getProgress(
+                        timings,
+                        linearProgress,
+                        timings.contentBeforeFadeOutDelay,
+                        timings.contentBeforeFadeOutDuration
+                    ) < 1
+                } else {
+                    getProgress(
+                        timings,
+                        linearProgress,
+                        timings.contentAfterFadeInDelay,
+                        timings.contentAfterFadeInDuration
+                    ) > 0
+                }
 
-            if (moveBackgroundLayerWhenAppIsVisible && !state.visible && !movedBackgroundLayer) {
-                // The expanding view is not visible, so the opening app is visible. If this is the
-                // first frame when it happens, trigger a one-off sync and move the background layer
-                // in its new container.
+            if (
+                controller.isLaunching &&
+                    moveBackgroundLayerWhenAppVisibilityChanges &&
+                    !state.visible &&
+                    !movedBackgroundLayer
+            ) {
+                // The expanding view is not visible, so the opening app is visible. If this is
+                // the first frame when it happens, trigger a one-off sync and move the
+                // background layer in its new container.
                 movedBackgroundLayer = true
 
                 transitionContainerOverlay.remove(windowBackgroundLayer)
@@ -362,6 +414,25 @@
                     openingWindowSyncView,
                     then = {}
                 )
+            } else if (
+                !controller.isLaunching &&
+                    moveBackgroundLayerWhenAppVisibilityChanges &&
+                    state.visible &&
+                    !movedBackgroundLayer
+            ) {
+                // The contracting view is now visible, so the closing app is not. If this is
+                // the first frame when it happens, trigger a one-off sync and move the
+                // background layer in its new container.
+                movedBackgroundLayer = true
+
+                openingWindowSyncViewOverlay!!.remove(windowBackgroundLayer)
+                transitionContainerOverlay.add(windowBackgroundLayer)
+
+                ViewRootSync.synchronizeNextDraw(
+                    openingWindowSyncView,
+                    transitionContainer,
+                    then = {}
+                )
             }
 
             val container =
@@ -376,19 +447,14 @@
                 state,
                 linearProgress,
                 container,
-                fadeOutWindowBackgroundLayer,
-                drawHole
+                fadeWindowBackgroundLayer,
+                drawHole,
+                controller.isLaunching
             )
             controller.onTransitionAnimationProgress(state, progress, linearProgress)
         }
 
-        animator.start()
-        return object : Animation {
-            override fun cancel() {
-                cancelled = true
-                animator.cancel()
-            }
-        }
+        return animator
     }
 
     /** Return whether we are expanding fully above the [transitionContainer]. */
@@ -405,8 +471,9 @@
         state: State,
         linearProgress: Float,
         transitionContainer: View,
-        fadeOutWindowBackgroundLayer: Boolean,
-        drawHole: Boolean
+        fadeWindowBackgroundLayer: Boolean,
+        drawHole: Boolean,
+        isLaunching: Boolean
     ) {
         // Update position.
         transitionContainer.getLocationOnScreen(transitionContainerLocation)
@@ -437,27 +504,64 @@
                 timings.contentBeforeFadeOutDelay,
                 timings.contentBeforeFadeOutDuration
             )
-        if (fadeInProgress < 1) {
-            val alpha =
-                interpolators.contentBeforeFadeOutInterpolator.getInterpolation(fadeInProgress)
-            drawable.alpha = (alpha * 0xFF).roundToInt()
-        } else if (fadeOutWindowBackgroundLayer) {
-            val fadeOutProgress =
-                getProgress(
-                    timings,
-                    linearProgress,
-                    timings.contentAfterFadeInDelay,
-                    timings.contentAfterFadeInDuration
-                )
-            val alpha =
-                1 - interpolators.contentAfterFadeInInterpolator.getInterpolation(fadeOutProgress)
-            drawable.alpha = (alpha * 0xFF).roundToInt()
 
-            if (drawHole) {
-                drawable.setXfermode(SRC_MODE)
+        if (isLaunching) {
+            if (fadeInProgress < 1) {
+                val alpha =
+                    interpolators.contentBeforeFadeOutInterpolator.getInterpolation(fadeInProgress)
+                drawable.alpha = (alpha * 0xFF).roundToInt()
+            } else if (fadeWindowBackgroundLayer) {
+                val fadeOutProgress =
+                    getProgress(
+                        timings,
+                        linearProgress,
+                        timings.contentAfterFadeInDelay,
+                        timings.contentAfterFadeInDuration
+                    )
+                val alpha =
+                    1 -
+                        interpolators.contentAfterFadeInInterpolator.getInterpolation(
+                            fadeOutProgress
+                        )
+                drawable.alpha = (alpha * 0xFF).roundToInt()
+
+                if (drawHole) {
+                    drawable.setXfermode(SRC_MODE)
+                }
+            } else {
+                drawable.alpha = 0xFF
             }
         } else {
-            drawable.alpha = 0xFF
+            if (fadeInProgress < 1 && fadeWindowBackgroundLayer) {
+                val alpha =
+                    interpolators.contentBeforeFadeOutInterpolator.getInterpolation(fadeInProgress)
+                drawable.alpha = (alpha * 0xFF).roundToInt()
+
+                if (drawHole) {
+                    drawable.setXfermode(SRC_MODE)
+                }
+            } else {
+                val fadeOutProgress =
+                    getProgress(
+                        timings,
+                        linearProgress,
+                        timings.contentAfterFadeInDelay,
+                        timings.contentAfterFadeInDuration
+                    )
+                val alpha =
+                    1 -
+                        interpolators.contentAfterFadeInInterpolator.getInterpolation(
+                            fadeOutProgress
+                        )
+                drawable.alpha = (alpha * 0xFF).roundToInt()
+                drawable.setXfermode(null)
+            }
+        }
+    }
+
+    private fun checkReturnAnimationFrameworkFlag() {
+        check(returnAnimationFrameworkLibrary()) {
+            "isLaunching cannot be false when the returnAnimationFrameworkLibrary flag is disabled"
         }
     }
 }
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt
index 974ee3a..c7f0a96 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt
@@ -168,6 +168,9 @@
 
             override var transitionContainer: ViewGroup = composeViewRoot.rootView as ViewGroup
 
+            // TODO(b/323863002): update to be dependant on usage.
+            override val isLaunching: Boolean = true
+
             override fun onTransitionAnimationEnd(isExpandingFullyAbove: Boolean) {
                 animatorState.value = null
             }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 182798e..4eb3a17 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -178,8 +178,6 @@
 import com.android.systemui.wallpapers.data.repository.WallpaperRepository;
 import com.android.wm.shell.keyguard.KeyguardTransitions;
 
-import dagger.Lazy;
-
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -189,6 +187,7 @@
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
+import dagger.Lazy;
 import kotlinx.coroutines.CoroutineDispatcher;
 
 /**
@@ -964,6 +963,13 @@
     @VisibleForTesting
     final ActivityTransitionAnimator.Controller mOccludeAnimationController =
             new ActivityTransitionAnimator.Controller() {
+                private boolean mIsLaunching = true;
+
+                @Override
+                public boolean isLaunching() {
+                    return mIsLaunching;
+                }
+
                 @Override
                 public void onTransitionAnimationStart(boolean isExpandingFullyAbove) {
                     mOccludeAnimationPlaying = true;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerOcclusionManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerOcclusionManager.kt
index aab90c3..585bd6a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerOcclusionManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerOcclusionManager.kt
@@ -263,6 +263,7 @@
     @VisibleForTesting
     val occludeAnimationController: ActivityTransitionAnimator.Controller =
         object : ActivityTransitionAnimator.Controller {
+            override val isLaunching: Boolean = true
 
             override var transitionContainer: ViewGroup
                 get() = keyguardViewController.get().getViewRootImpl().view as ViewGroup
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorController.kt
index eb0870a..2b7df7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorController.kt
@@ -75,6 +75,8 @@
     private val notificationEntry = notification.entry
     private val notificationKey = notificationEntry.sbn.key
 
+    override val isLaunching: Boolean = true
+
     override var transitionContainer: ViewGroup
         get() = notification.rootView as ViewGroup
         set(ignored) {
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 572a6c1..0dbbe63 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -224,6 +224,5 @@
 
     <instrumentation android:name="android.testing.TestableInstrumentation"
         android:targetPackage="com.android.systemui.tests"
-        android:label="Tests for SystemUI">
-    </instrumentation>
+        android:label="Tests for SystemUI" />
 </manifest>
diff --git a/packages/SystemUI/tests/AndroidTest.xml b/packages/SystemUI/tests/AndroidTest.xml
index cd2a62d..2de5faf 100644
--- a/packages/SystemUI/tests/AndroidTest.xml
+++ b/packages/SystemUI/tests/AndroidTest.xml
@@ -23,6 +23,15 @@
         <option name="force-root" value="true" />
     </target_preparer>
 
+    <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+        <option name="screen-always-on" value="on" />
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
+        <option name="run-command" value="wm dismiss-keyguard" />
+    </target_preparer>
+
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="framework-base-presubmit" />
     <option name="test-tag" value="SystemUITests" />
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenLaunching.json b/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenLaunching.json
new file mode 100644
index 0000000..60bff17
--- /dev/null
+++ b/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenLaunching.json
@@ -0,0 +1,393 @@
+{
+  "frame_ids": [
+    "before",
+    0,
+    26,
+    52,
+    78,
+    105,
+    131,
+    157,
+    184,
+    210,
+    236,
+    263,
+    289,
+    315,
+    342,
+    368,
+    394,
+    421,
+    447,
+    473,
+    500
+  ],
+  "features": [
+    {
+      "name": "bounds",
+      "type": "rect",
+      "data_points": [
+        {
+          "left": 0,
+          "top": 0,
+          "right": 0,
+          "bottom": 0
+        },
+        {
+          "left": 100,
+          "top": 300,
+          "right": 200,
+          "bottom": 400
+        },
+        {
+          "left": 98,
+          "top": 293,
+          "right": 203,
+          "bottom": 407
+        },
+        {
+          "left": 91,
+          "top": 269,
+          "right": 213,
+          "bottom": 430
+        },
+        {
+          "left": 71,
+          "top": 206,
+          "right": 240,
+          "bottom": 491
+        },
+        {
+          "left": 34,
+          "top": 98,
+          "right": 283,
+          "bottom": 595
+        },
+        {
+          "left": 22,
+          "top": 63,
+          "right": 296,
+          "bottom": 629
+        },
+        {
+          "left": 15,
+          "top": 44,
+          "right": 303,
+          "bottom": 648
+        },
+        {
+          "left": 11,
+          "top": 32,
+          "right": 308,
+          "bottom": 659
+        },
+        {
+          "left": 8,
+          "top": 23,
+          "right": 311,
+          "bottom": 667
+        },
+        {
+          "left": 6,
+          "top": 18,
+          "right": 313,
+          "bottom": 673
+        },
+        {
+          "left": 5,
+          "top": 13,
+          "right": 315,
+          "bottom": 677
+        },
+        {
+          "left": 3,
+          "top": 9,
+          "right": 316,
+          "bottom": 681
+        },
+        {
+          "left": 2,
+          "top": 7,
+          "right": 317,
+          "bottom": 683
+        },
+        {
+          "left": 2,
+          "top": 5,
+          "right": 318,
+          "bottom": 685
+        },
+        {
+          "left": 1,
+          "top": 3,
+          "right": 319,
+          "bottom": 687
+        },
+        {
+          "left": 1,
+          "top": 2,
+          "right": 319,
+          "bottom": 688
+        },
+        {
+          "left": 0,
+          "top": 1,
+          "right": 320,
+          "bottom": 689
+        },
+        {
+          "left": 0,
+          "top": 0,
+          "right": 320,
+          "bottom": 690
+        },
+        {
+          "left": 0,
+          "top": 0,
+          "right": 320,
+          "bottom": 690
+        },
+        {
+          "left": 0,
+          "top": 0,
+          "right": 320,
+          "bottom": 690
+        }
+      ]
+    },
+    {
+      "name": "corner_radii",
+      "type": "cornerRadii",
+      "data_points": [
+        null,
+        {
+          "top_left_x": 10,
+          "top_left_y": 10,
+          "top_right_x": 10,
+          "top_right_y": 10,
+          "bottom_right_x": 20,
+          "bottom_right_y": 20,
+          "bottom_left_x": 20,
+          "bottom_left_y": 20
+        },
+        {
+          "top_left_x": 9.762664,
+          "top_left_y": 9.762664,
+          "top_right_x": 9.762664,
+          "top_right_y": 9.762664,
+          "bottom_right_x": 19.525328,
+          "bottom_right_y": 19.525328,
+          "bottom_left_x": 19.525328,
+          "bottom_left_y": 19.525328
+        },
+        {
+          "top_left_x": 8.969244,
+          "top_left_y": 8.969244,
+          "top_right_x": 8.969244,
+          "top_right_y": 8.969244,
+          "bottom_right_x": 17.938488,
+          "bottom_right_y": 17.938488,
+          "bottom_left_x": 17.938488,
+          "bottom_left_y": 17.938488
+        },
+        {
+          "top_left_x": 6.8709626,
+          "top_left_y": 6.8709626,
+          "top_right_x": 6.8709626,
+          "top_right_y": 6.8709626,
+          "bottom_right_x": 13.741925,
+          "bottom_right_y": 13.741925,
+          "bottom_left_x": 13.741925,
+          "bottom_left_y": 13.741925
+        },
+        {
+          "top_left_x": 3.260561,
+          "top_left_y": 3.260561,
+          "top_right_x": 3.260561,
+          "top_right_y": 3.260561,
+          "bottom_right_x": 6.521122,
+          "bottom_right_y": 6.521122,
+          "bottom_left_x": 6.521122,
+          "bottom_left_y": 6.521122
+        },
+        {
+          "top_left_x": 2.0915751,
+          "top_left_y": 2.0915751,
+          "top_right_x": 2.0915751,
+          "top_right_y": 2.0915751,
+          "bottom_right_x": 4.1831503,
+          "bottom_right_y": 4.1831503,
+          "bottom_left_x": 4.1831503,
+          "bottom_left_y": 4.1831503
+        },
+        {
+          "top_left_x": 1.4640827,
+          "top_left_y": 1.4640827,
+          "top_right_x": 1.4640827,
+          "top_right_y": 1.4640827,
+          "bottom_right_x": 2.9281654,
+          "bottom_right_y": 2.9281654,
+          "bottom_left_x": 2.9281654,
+          "bottom_left_y": 2.9281654
+        },
+        {
+          "top_left_x": 1.057313,
+          "top_left_y": 1.057313,
+          "top_right_x": 1.057313,
+          "top_right_y": 1.057313,
+          "bottom_right_x": 2.114626,
+          "bottom_right_y": 2.114626,
+          "bottom_left_x": 2.114626,
+          "bottom_left_y": 2.114626
+        },
+        {
+          "top_left_x": 0.7824335,
+          "top_left_y": 0.7824335,
+          "top_right_x": 0.7824335,
+          "top_right_y": 0.7824335,
+          "bottom_right_x": 1.564867,
+          "bottom_right_y": 1.564867,
+          "bottom_left_x": 1.564867,
+          "bottom_left_y": 1.564867
+        },
+        {
+          "top_left_x": 0.5863056,
+          "top_left_y": 0.5863056,
+          "top_right_x": 0.5863056,
+          "top_right_y": 0.5863056,
+          "bottom_right_x": 1.1726112,
+          "bottom_right_y": 1.1726112,
+          "bottom_left_x": 1.1726112,
+          "bottom_left_y": 1.1726112
+        },
+        {
+          "top_left_x": 0.4332962,
+          "top_left_y": 0.4332962,
+          "top_right_x": 0.4332962,
+          "top_right_y": 0.4332962,
+          "bottom_right_x": 0.8665924,
+          "bottom_right_y": 0.8665924,
+          "bottom_left_x": 0.8665924,
+          "bottom_left_y": 0.8665924
+        },
+        {
+          "top_left_x": 0.3145876,
+          "top_left_y": 0.3145876,
+          "top_right_x": 0.3145876,
+          "top_right_y": 0.3145876,
+          "bottom_right_x": 0.6291752,
+          "bottom_right_y": 0.6291752,
+          "bottom_left_x": 0.6291752,
+          "bottom_left_y": 0.6291752
+        },
+        {
+          "top_left_x": 0.22506618,
+          "top_left_y": 0.22506618,
+          "top_right_x": 0.22506618,
+          "top_right_y": 0.22506618,
+          "bottom_right_x": 0.45013237,
+          "bottom_right_y": 0.45013237,
+          "bottom_left_x": 0.45013237,
+          "bottom_left_y": 0.45013237
+        },
+        {
+          "top_left_x": 0.15591621,
+          "top_left_y": 0.15591621,
+          "top_right_x": 0.15591621,
+          "top_right_y": 0.15591621,
+          "bottom_right_x": 0.31183243,
+          "bottom_right_y": 0.31183243,
+          "bottom_left_x": 0.31183243,
+          "bottom_left_y": 0.31183243
+        },
+        {
+          "top_left_x": 0.100948334,
+          "top_left_y": 0.100948334,
+          "top_right_x": 0.100948334,
+          "top_right_y": 0.100948334,
+          "bottom_right_x": 0.20189667,
+          "bottom_right_y": 0.20189667,
+          "bottom_left_x": 0.20189667,
+          "bottom_left_y": 0.20189667
+        },
+        {
+          "top_left_x": 0.06496239,
+          "top_left_y": 0.06496239,
+          "top_right_x": 0.06496239,
+          "top_right_y": 0.06496239,
+          "bottom_right_x": 0.12992477,
+          "bottom_right_y": 0.12992477,
+          "bottom_left_x": 0.12992477,
+          "bottom_left_y": 0.12992477
+        },
+        {
+          "top_left_x": 0.03526497,
+          "top_left_y": 0.03526497,
+          "top_right_x": 0.03526497,
+          "top_right_y": 0.03526497,
+          "bottom_right_x": 0.07052994,
+          "bottom_right_y": 0.07052994,
+          "bottom_left_x": 0.07052994,
+          "bottom_left_y": 0.07052994
+        },
+        {
+          "top_left_x": 0.014661789,
+          "top_left_y": 0.014661789,
+          "top_right_x": 0.014661789,
+          "top_right_y": 0.014661789,
+          "bottom_right_x": 0.029323578,
+          "bottom_right_y": 0.029323578,
+          "bottom_left_x": 0.029323578,
+          "bottom_left_y": 0.029323578
+        },
+        {
+          "top_left_x": 0.0041856766,
+          "top_left_y": 0.0041856766,
+          "top_right_x": 0.0041856766,
+          "top_right_y": 0.0041856766,
+          "bottom_right_x": 0.008371353,
+          "bottom_right_y": 0.008371353,
+          "bottom_left_x": 0.008371353,
+          "bottom_left_y": 0.008371353
+        },
+        {
+          "top_left_x": 0,
+          "top_left_y": 0,
+          "top_right_x": 0,
+          "top_right_y": 0,
+          "bottom_right_x": 0,
+          "bottom_right_y": 0,
+          "bottom_left_x": 0,
+          "bottom_left_y": 0
+        }
+      ]
+    },
+    {
+      "name": "alpha",
+      "type": "int",
+      "data_points": [
+        0,
+        0,
+        115,
+        178,
+        217,
+        241,
+        253,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenReturning.json b/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenReturning.json
new file mode 100644
index 0000000..ea768c0
--- /dev/null
+++ b/packages/SystemUI/tests/goldens/backgroundAnimationWithoutFade_whenReturning.json
@@ -0,0 +1,393 @@
+{
+  "frame_ids": [
+    "before",
+    0,
+    26,
+    52,
+    78,
+    105,
+    131,
+    157,
+    184,
+    210,
+    236,
+    263,
+    289,
+    315,
+    342,
+    368,
+    394,
+    421,
+    447,
+    473,
+    500
+  ],
+  "features": [
+    {
+      "name": "bounds",
+      "type": "rect",
+      "data_points": [
+        {
+          "left": 0,
+          "top": 0,
+          "right": 0,
+          "bottom": 0
+        },
+        {
+          "left": 100,
+          "top": 300,
+          "right": 200,
+          "bottom": 400
+        },
+        {
+          "left": 98,
+          "top": 293,
+          "right": 203,
+          "bottom": 407
+        },
+        {
+          "left": 91,
+          "top": 269,
+          "right": 213,
+          "bottom": 430
+        },
+        {
+          "left": 71,
+          "top": 206,
+          "right": 240,
+          "bottom": 491
+        },
+        {
+          "left": 34,
+          "top": 98,
+          "right": 283,
+          "bottom": 595
+        },
+        {
+          "left": 22,
+          "top": 63,
+          "right": 296,
+          "bottom": 629
+        },
+        {
+          "left": 15,
+          "top": 44,
+          "right": 303,
+          "bottom": 648
+        },
+        {
+          "left": 11,
+          "top": 32,
+          "right": 308,
+          "bottom": 659
+        },
+        {
+          "left": 8,
+          "top": 23,
+          "right": 311,
+          "bottom": 667
+        },
+        {
+          "left": 6,
+          "top": 18,
+          "right": 313,
+          "bottom": 673
+        },
+        {
+          "left": 5,
+          "top": 13,
+          "right": 315,
+          "bottom": 677
+        },
+        {
+          "left": 3,
+          "top": 9,
+          "right": 316,
+          "bottom": 681
+        },
+        {
+          "left": 2,
+          "top": 7,
+          "right": 317,
+          "bottom": 683
+        },
+        {
+          "left": 2,
+          "top": 5,
+          "right": 318,
+          "bottom": 685
+        },
+        {
+          "left": 1,
+          "top": 3,
+          "right": 319,
+          "bottom": 687
+        },
+        {
+          "left": 1,
+          "top": 2,
+          "right": 319,
+          "bottom": 688
+        },
+        {
+          "left": 0,
+          "top": 1,
+          "right": 320,
+          "bottom": 689
+        },
+        {
+          "left": 0,
+          "top": 0,
+          "right": 320,
+          "bottom": 690
+        },
+        {
+          "left": 0,
+          "top": 0,
+          "right": 320,
+          "bottom": 690
+        },
+        {
+          "left": 0,
+          "top": 0,
+          "right": 320,
+          "bottom": 690
+        }
+      ]
+    },
+    {
+      "name": "corner_radii",
+      "type": "cornerRadii",
+      "data_points": [
+        null,
+        {
+          "top_left_x": 10,
+          "top_left_y": 10,
+          "top_right_x": 10,
+          "top_right_y": 10,
+          "bottom_right_x": 20,
+          "bottom_right_y": 20,
+          "bottom_left_x": 20,
+          "bottom_left_y": 20
+        },
+        {
+          "top_left_x": 9.762664,
+          "top_left_y": 9.762664,
+          "top_right_x": 9.762664,
+          "top_right_y": 9.762664,
+          "bottom_right_x": 19.525328,
+          "bottom_right_y": 19.525328,
+          "bottom_left_x": 19.525328,
+          "bottom_left_y": 19.525328
+        },
+        {
+          "top_left_x": 8.969244,
+          "top_left_y": 8.969244,
+          "top_right_x": 8.969244,
+          "top_right_y": 8.969244,
+          "bottom_right_x": 17.938488,
+          "bottom_right_y": 17.938488,
+          "bottom_left_x": 17.938488,
+          "bottom_left_y": 17.938488
+        },
+        {
+          "top_left_x": 6.8709626,
+          "top_left_y": 6.8709626,
+          "top_right_x": 6.8709626,
+          "top_right_y": 6.8709626,
+          "bottom_right_x": 13.741925,
+          "bottom_right_y": 13.741925,
+          "bottom_left_x": 13.741925,
+          "bottom_left_y": 13.741925
+        },
+        {
+          "top_left_x": 3.260561,
+          "top_left_y": 3.260561,
+          "top_right_x": 3.260561,
+          "top_right_y": 3.260561,
+          "bottom_right_x": 6.521122,
+          "bottom_right_y": 6.521122,
+          "bottom_left_x": 6.521122,
+          "bottom_left_y": 6.521122
+        },
+        {
+          "top_left_x": 2.0915751,
+          "top_left_y": 2.0915751,
+          "top_right_x": 2.0915751,
+          "top_right_y": 2.0915751,
+          "bottom_right_x": 4.1831503,
+          "bottom_right_y": 4.1831503,
+          "bottom_left_x": 4.1831503,
+          "bottom_left_y": 4.1831503
+        },
+        {
+          "top_left_x": 1.4640827,
+          "top_left_y": 1.4640827,
+          "top_right_x": 1.4640827,
+          "top_right_y": 1.4640827,
+          "bottom_right_x": 2.9281654,
+          "bottom_right_y": 2.9281654,
+          "bottom_left_x": 2.9281654,
+          "bottom_left_y": 2.9281654
+        },
+        {
+          "top_left_x": 1.057313,
+          "top_left_y": 1.057313,
+          "top_right_x": 1.057313,
+          "top_right_y": 1.057313,
+          "bottom_right_x": 2.114626,
+          "bottom_right_y": 2.114626,
+          "bottom_left_x": 2.114626,
+          "bottom_left_y": 2.114626
+        },
+        {
+          "top_left_x": 0.7824335,
+          "top_left_y": 0.7824335,
+          "top_right_x": 0.7824335,
+          "top_right_y": 0.7824335,
+          "bottom_right_x": 1.564867,
+          "bottom_right_y": 1.564867,
+          "bottom_left_x": 1.564867,
+          "bottom_left_y": 1.564867
+        },
+        {
+          "top_left_x": 0.5863056,
+          "top_left_y": 0.5863056,
+          "top_right_x": 0.5863056,
+          "top_right_y": 0.5863056,
+          "bottom_right_x": 1.1726112,
+          "bottom_right_y": 1.1726112,
+          "bottom_left_x": 1.1726112,
+          "bottom_left_y": 1.1726112
+        },
+        {
+          "top_left_x": 0.4332962,
+          "top_left_y": 0.4332962,
+          "top_right_x": 0.4332962,
+          "top_right_y": 0.4332962,
+          "bottom_right_x": 0.8665924,
+          "bottom_right_y": 0.8665924,
+          "bottom_left_x": 0.8665924,
+          "bottom_left_y": 0.8665924
+        },
+        {
+          "top_left_x": 0.3145876,
+          "top_left_y": 0.3145876,
+          "top_right_x": 0.3145876,
+          "top_right_y": 0.3145876,
+          "bottom_right_x": 0.6291752,
+          "bottom_right_y": 0.6291752,
+          "bottom_left_x": 0.6291752,
+          "bottom_left_y": 0.6291752
+        },
+        {
+          "top_left_x": 0.22506618,
+          "top_left_y": 0.22506618,
+          "top_right_x": 0.22506618,
+          "top_right_y": 0.22506618,
+          "bottom_right_x": 0.45013237,
+          "bottom_right_y": 0.45013237,
+          "bottom_left_x": 0.45013237,
+          "bottom_left_y": 0.45013237
+        },
+        {
+          "top_left_x": 0.15591621,
+          "top_left_y": 0.15591621,
+          "top_right_x": 0.15591621,
+          "top_right_y": 0.15591621,
+          "bottom_right_x": 0.31183243,
+          "bottom_right_y": 0.31183243,
+          "bottom_left_x": 0.31183243,
+          "bottom_left_y": 0.31183243
+        },
+        {
+          "top_left_x": 0.100948334,
+          "top_left_y": 0.100948334,
+          "top_right_x": 0.100948334,
+          "top_right_y": 0.100948334,
+          "bottom_right_x": 0.20189667,
+          "bottom_right_y": 0.20189667,
+          "bottom_left_x": 0.20189667,
+          "bottom_left_y": 0.20189667
+        },
+        {
+          "top_left_x": 0.06496239,
+          "top_left_y": 0.06496239,
+          "top_right_x": 0.06496239,
+          "top_right_y": 0.06496239,
+          "bottom_right_x": 0.12992477,
+          "bottom_right_y": 0.12992477,
+          "bottom_left_x": 0.12992477,
+          "bottom_left_y": 0.12992477
+        },
+        {
+          "top_left_x": 0.03526497,
+          "top_left_y": 0.03526497,
+          "top_right_x": 0.03526497,
+          "top_right_y": 0.03526497,
+          "bottom_right_x": 0.07052994,
+          "bottom_right_y": 0.07052994,
+          "bottom_left_x": 0.07052994,
+          "bottom_left_y": 0.07052994
+        },
+        {
+          "top_left_x": 0.014661789,
+          "top_left_y": 0.014661789,
+          "top_right_x": 0.014661789,
+          "top_right_y": 0.014661789,
+          "bottom_right_x": 0.029323578,
+          "bottom_right_y": 0.029323578,
+          "bottom_left_x": 0.029323578,
+          "bottom_left_y": 0.029323578
+        },
+        {
+          "top_left_x": 0.0041856766,
+          "top_left_y": 0.0041856766,
+          "top_right_x": 0.0041856766,
+          "top_right_y": 0.0041856766,
+          "bottom_right_x": 0.008371353,
+          "bottom_right_y": 0.008371353,
+          "bottom_left_x": 0.008371353,
+          "bottom_left_y": 0.008371353
+        },
+        {
+          "top_left_x": 0,
+          "top_left_y": 0,
+          "top_right_x": 0,
+          "top_right_y": 0,
+          "bottom_right_x": 0,
+          "bottom_right_y": 0,
+          "bottom_left_x": 0,
+          "bottom_left_y": 0
+        }
+      ]
+    },
+    {
+      "name": "alpha",
+      "type": "int",
+      "data_points": [
+        0,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        239,
+        183,
+        135,
+        91,
+        53,
+        23,
+        5,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimation_whenLaunching.json b/packages/SystemUI/tests/goldens/backgroundAnimation_whenLaunching.json
new file mode 100644
index 0000000..608e633
--- /dev/null
+++ b/packages/SystemUI/tests/goldens/backgroundAnimation_whenLaunching.json
@@ -0,0 +1,393 @@
+{
+  "frame_ids": [
+    "before",
+    0,
+    26,
+    52,
+    78,
+    105,
+    131,
+    157,
+    184,
+    210,
+    236,
+    263,
+    289,
+    315,
+    342,
+    368,
+    394,
+    421,
+    447,
+    473,
+    500
+  ],
+  "features": [
+    {
+      "name": "bounds",
+      "type": "rect",
+      "data_points": [
+        {
+          "left": 0,
+          "top": 0,
+          "right": 0,
+          "bottom": 0
+        },
+        {
+          "left": 100,
+          "top": 300,
+          "right": 200,
+          "bottom": 400
+        },
+        {
+          "left": 98,
+          "top": 293,
+          "right": 203,
+          "bottom": 407
+        },
+        {
+          "left": 91,
+          "top": 269,
+          "right": 213,
+          "bottom": 430
+        },
+        {
+          "left": 71,
+          "top": 206,
+          "right": 240,
+          "bottom": 491
+        },
+        {
+          "left": 34,
+          "top": 98,
+          "right": 283,
+          "bottom": 595
+        },
+        {
+          "left": 22,
+          "top": 63,
+          "right": 296,
+          "bottom": 629
+        },
+        {
+          "left": 15,
+          "top": 44,
+          "right": 303,
+          "bottom": 648
+        },
+        {
+          "left": 11,
+          "top": 32,
+          "right": 308,
+          "bottom": 659
+        },
+        {
+          "left": 8,
+          "top": 23,
+          "right": 311,
+          "bottom": 667
+        },
+        {
+          "left": 6,
+          "top": 18,
+          "right": 313,
+          "bottom": 673
+        },
+        {
+          "left": 5,
+          "top": 13,
+          "right": 315,
+          "bottom": 677
+        },
+        {
+          "left": 3,
+          "top": 9,
+          "right": 316,
+          "bottom": 681
+        },
+        {
+          "left": 2,
+          "top": 7,
+          "right": 317,
+          "bottom": 683
+        },
+        {
+          "left": 2,
+          "top": 5,
+          "right": 318,
+          "bottom": 685
+        },
+        {
+          "left": 1,
+          "top": 3,
+          "right": 319,
+          "bottom": 687
+        },
+        {
+          "left": 1,
+          "top": 2,
+          "right": 319,
+          "bottom": 688
+        },
+        {
+          "left": 0,
+          "top": 1,
+          "right": 320,
+          "bottom": 689
+        },
+        {
+          "left": 0,
+          "top": 0,
+          "right": 320,
+          "bottom": 690
+        },
+        {
+          "left": 0,
+          "top": 0,
+          "right": 320,
+          "bottom": 690
+        },
+        {
+          "left": 0,
+          "top": 0,
+          "right": 320,
+          "bottom": 690
+        }
+      ]
+    },
+    {
+      "name": "corner_radii",
+      "type": "cornerRadii",
+      "data_points": [
+        null,
+        {
+          "top_left_x": 10,
+          "top_left_y": 10,
+          "top_right_x": 10,
+          "top_right_y": 10,
+          "bottom_right_x": 20,
+          "bottom_right_y": 20,
+          "bottom_left_x": 20,
+          "bottom_left_y": 20
+        },
+        {
+          "top_left_x": 9.762664,
+          "top_left_y": 9.762664,
+          "top_right_x": 9.762664,
+          "top_right_y": 9.762664,
+          "bottom_right_x": 19.525328,
+          "bottom_right_y": 19.525328,
+          "bottom_left_x": 19.525328,
+          "bottom_left_y": 19.525328
+        },
+        {
+          "top_left_x": 8.969244,
+          "top_left_y": 8.969244,
+          "top_right_x": 8.969244,
+          "top_right_y": 8.969244,
+          "bottom_right_x": 17.938488,
+          "bottom_right_y": 17.938488,
+          "bottom_left_x": 17.938488,
+          "bottom_left_y": 17.938488
+        },
+        {
+          "top_left_x": 6.8709626,
+          "top_left_y": 6.8709626,
+          "top_right_x": 6.8709626,
+          "top_right_y": 6.8709626,
+          "bottom_right_x": 13.741925,
+          "bottom_right_y": 13.741925,
+          "bottom_left_x": 13.741925,
+          "bottom_left_y": 13.741925
+        },
+        {
+          "top_left_x": 3.260561,
+          "top_left_y": 3.260561,
+          "top_right_x": 3.260561,
+          "top_right_y": 3.260561,
+          "bottom_right_x": 6.521122,
+          "bottom_right_y": 6.521122,
+          "bottom_left_x": 6.521122,
+          "bottom_left_y": 6.521122
+        },
+        {
+          "top_left_x": 2.0915751,
+          "top_left_y": 2.0915751,
+          "top_right_x": 2.0915751,
+          "top_right_y": 2.0915751,
+          "bottom_right_x": 4.1831503,
+          "bottom_right_y": 4.1831503,
+          "bottom_left_x": 4.1831503,
+          "bottom_left_y": 4.1831503
+        },
+        {
+          "top_left_x": 1.4640827,
+          "top_left_y": 1.4640827,
+          "top_right_x": 1.4640827,
+          "top_right_y": 1.4640827,
+          "bottom_right_x": 2.9281654,
+          "bottom_right_y": 2.9281654,
+          "bottom_left_x": 2.9281654,
+          "bottom_left_y": 2.9281654
+        },
+        {
+          "top_left_x": 1.057313,
+          "top_left_y": 1.057313,
+          "top_right_x": 1.057313,
+          "top_right_y": 1.057313,
+          "bottom_right_x": 2.114626,
+          "bottom_right_y": 2.114626,
+          "bottom_left_x": 2.114626,
+          "bottom_left_y": 2.114626
+        },
+        {
+          "top_left_x": 0.7824335,
+          "top_left_y": 0.7824335,
+          "top_right_x": 0.7824335,
+          "top_right_y": 0.7824335,
+          "bottom_right_x": 1.564867,
+          "bottom_right_y": 1.564867,
+          "bottom_left_x": 1.564867,
+          "bottom_left_y": 1.564867
+        },
+        {
+          "top_left_x": 0.5863056,
+          "top_left_y": 0.5863056,
+          "top_right_x": 0.5863056,
+          "top_right_y": 0.5863056,
+          "bottom_right_x": 1.1726112,
+          "bottom_right_y": 1.1726112,
+          "bottom_left_x": 1.1726112,
+          "bottom_left_y": 1.1726112
+        },
+        {
+          "top_left_x": 0.4332962,
+          "top_left_y": 0.4332962,
+          "top_right_x": 0.4332962,
+          "top_right_y": 0.4332962,
+          "bottom_right_x": 0.8665924,
+          "bottom_right_y": 0.8665924,
+          "bottom_left_x": 0.8665924,
+          "bottom_left_y": 0.8665924
+        },
+        {
+          "top_left_x": 0.3145876,
+          "top_left_y": 0.3145876,
+          "top_right_x": 0.3145876,
+          "top_right_y": 0.3145876,
+          "bottom_right_x": 0.6291752,
+          "bottom_right_y": 0.6291752,
+          "bottom_left_x": 0.6291752,
+          "bottom_left_y": 0.6291752
+        },
+        {
+          "top_left_x": 0.22506618,
+          "top_left_y": 0.22506618,
+          "top_right_x": 0.22506618,
+          "top_right_y": 0.22506618,
+          "bottom_right_x": 0.45013237,
+          "bottom_right_y": 0.45013237,
+          "bottom_left_x": 0.45013237,
+          "bottom_left_y": 0.45013237
+        },
+        {
+          "top_left_x": 0.15591621,
+          "top_left_y": 0.15591621,
+          "top_right_x": 0.15591621,
+          "top_right_y": 0.15591621,
+          "bottom_right_x": 0.31183243,
+          "bottom_right_y": 0.31183243,
+          "bottom_left_x": 0.31183243,
+          "bottom_left_y": 0.31183243
+        },
+        {
+          "top_left_x": 0.100948334,
+          "top_left_y": 0.100948334,
+          "top_right_x": 0.100948334,
+          "top_right_y": 0.100948334,
+          "bottom_right_x": 0.20189667,
+          "bottom_right_y": 0.20189667,
+          "bottom_left_x": 0.20189667,
+          "bottom_left_y": 0.20189667
+        },
+        {
+          "top_left_x": 0.06496239,
+          "top_left_y": 0.06496239,
+          "top_right_x": 0.06496239,
+          "top_right_y": 0.06496239,
+          "bottom_right_x": 0.12992477,
+          "bottom_right_y": 0.12992477,
+          "bottom_left_x": 0.12992477,
+          "bottom_left_y": 0.12992477
+        },
+        {
+          "top_left_x": 0.03526497,
+          "top_left_y": 0.03526497,
+          "top_right_x": 0.03526497,
+          "top_right_y": 0.03526497,
+          "bottom_right_x": 0.07052994,
+          "bottom_right_y": 0.07052994,
+          "bottom_left_x": 0.07052994,
+          "bottom_left_y": 0.07052994
+        },
+        {
+          "top_left_x": 0.014661789,
+          "top_left_y": 0.014661789,
+          "top_right_x": 0.014661789,
+          "top_right_y": 0.014661789,
+          "bottom_right_x": 0.029323578,
+          "bottom_right_y": 0.029323578,
+          "bottom_left_x": 0.029323578,
+          "bottom_left_y": 0.029323578
+        },
+        {
+          "top_left_x": 0.0041856766,
+          "top_left_y": 0.0041856766,
+          "top_right_x": 0.0041856766,
+          "top_right_y": 0.0041856766,
+          "bottom_right_x": 0.008371353,
+          "bottom_right_y": 0.008371353,
+          "bottom_left_x": 0.008371353,
+          "bottom_left_y": 0.008371353
+        },
+        {
+          "top_left_x": 0,
+          "top_left_y": 0,
+          "top_right_x": 0,
+          "top_right_y": 0,
+          "bottom_right_x": 0,
+          "bottom_right_y": 0,
+          "bottom_left_x": 0,
+          "bottom_left_y": 0
+        }
+      ]
+    },
+    {
+      "name": "alpha",
+      "type": "int",
+      "data_points": [
+        0,
+        0,
+        115,
+        178,
+        217,
+        241,
+        253,
+        239,
+        183,
+        135,
+        91,
+        53,
+        23,
+        5,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimation_whenReturning.json b/packages/SystemUI/tests/goldens/backgroundAnimation_whenReturning.json
new file mode 100644
index 0000000..608e633
--- /dev/null
+++ b/packages/SystemUI/tests/goldens/backgroundAnimation_whenReturning.json
@@ -0,0 +1,393 @@
+{
+  "frame_ids": [
+    "before",
+    0,
+    26,
+    52,
+    78,
+    105,
+    131,
+    157,
+    184,
+    210,
+    236,
+    263,
+    289,
+    315,
+    342,
+    368,
+    394,
+    421,
+    447,
+    473,
+    500
+  ],
+  "features": [
+    {
+      "name": "bounds",
+      "type": "rect",
+      "data_points": [
+        {
+          "left": 0,
+          "top": 0,
+          "right": 0,
+          "bottom": 0
+        },
+        {
+          "left": 100,
+          "top": 300,
+          "right": 200,
+          "bottom": 400
+        },
+        {
+          "left": 98,
+          "top": 293,
+          "right": 203,
+          "bottom": 407
+        },
+        {
+          "left": 91,
+          "top": 269,
+          "right": 213,
+          "bottom": 430
+        },
+        {
+          "left": 71,
+          "top": 206,
+          "right": 240,
+          "bottom": 491
+        },
+        {
+          "left": 34,
+          "top": 98,
+          "right": 283,
+          "bottom": 595
+        },
+        {
+          "left": 22,
+          "top": 63,
+          "right": 296,
+          "bottom": 629
+        },
+        {
+          "left": 15,
+          "top": 44,
+          "right": 303,
+          "bottom": 648
+        },
+        {
+          "left": 11,
+          "top": 32,
+          "right": 308,
+          "bottom": 659
+        },
+        {
+          "left": 8,
+          "top": 23,
+          "right": 311,
+          "bottom": 667
+        },
+        {
+          "left": 6,
+          "top": 18,
+          "right": 313,
+          "bottom": 673
+        },
+        {
+          "left": 5,
+          "top": 13,
+          "right": 315,
+          "bottom": 677
+        },
+        {
+          "left": 3,
+          "top": 9,
+          "right": 316,
+          "bottom": 681
+        },
+        {
+          "left": 2,
+          "top": 7,
+          "right": 317,
+          "bottom": 683
+        },
+        {
+          "left": 2,
+          "top": 5,
+          "right": 318,
+          "bottom": 685
+        },
+        {
+          "left": 1,
+          "top": 3,
+          "right": 319,
+          "bottom": 687
+        },
+        {
+          "left": 1,
+          "top": 2,
+          "right": 319,
+          "bottom": 688
+        },
+        {
+          "left": 0,
+          "top": 1,
+          "right": 320,
+          "bottom": 689
+        },
+        {
+          "left": 0,
+          "top": 0,
+          "right": 320,
+          "bottom": 690
+        },
+        {
+          "left": 0,
+          "top": 0,
+          "right": 320,
+          "bottom": 690
+        },
+        {
+          "left": 0,
+          "top": 0,
+          "right": 320,
+          "bottom": 690
+        }
+      ]
+    },
+    {
+      "name": "corner_radii",
+      "type": "cornerRadii",
+      "data_points": [
+        null,
+        {
+          "top_left_x": 10,
+          "top_left_y": 10,
+          "top_right_x": 10,
+          "top_right_y": 10,
+          "bottom_right_x": 20,
+          "bottom_right_y": 20,
+          "bottom_left_x": 20,
+          "bottom_left_y": 20
+        },
+        {
+          "top_left_x": 9.762664,
+          "top_left_y": 9.762664,
+          "top_right_x": 9.762664,
+          "top_right_y": 9.762664,
+          "bottom_right_x": 19.525328,
+          "bottom_right_y": 19.525328,
+          "bottom_left_x": 19.525328,
+          "bottom_left_y": 19.525328
+        },
+        {
+          "top_left_x": 8.969244,
+          "top_left_y": 8.969244,
+          "top_right_x": 8.969244,
+          "top_right_y": 8.969244,
+          "bottom_right_x": 17.938488,
+          "bottom_right_y": 17.938488,
+          "bottom_left_x": 17.938488,
+          "bottom_left_y": 17.938488
+        },
+        {
+          "top_left_x": 6.8709626,
+          "top_left_y": 6.8709626,
+          "top_right_x": 6.8709626,
+          "top_right_y": 6.8709626,
+          "bottom_right_x": 13.741925,
+          "bottom_right_y": 13.741925,
+          "bottom_left_x": 13.741925,
+          "bottom_left_y": 13.741925
+        },
+        {
+          "top_left_x": 3.260561,
+          "top_left_y": 3.260561,
+          "top_right_x": 3.260561,
+          "top_right_y": 3.260561,
+          "bottom_right_x": 6.521122,
+          "bottom_right_y": 6.521122,
+          "bottom_left_x": 6.521122,
+          "bottom_left_y": 6.521122
+        },
+        {
+          "top_left_x": 2.0915751,
+          "top_left_y": 2.0915751,
+          "top_right_x": 2.0915751,
+          "top_right_y": 2.0915751,
+          "bottom_right_x": 4.1831503,
+          "bottom_right_y": 4.1831503,
+          "bottom_left_x": 4.1831503,
+          "bottom_left_y": 4.1831503
+        },
+        {
+          "top_left_x": 1.4640827,
+          "top_left_y": 1.4640827,
+          "top_right_x": 1.4640827,
+          "top_right_y": 1.4640827,
+          "bottom_right_x": 2.9281654,
+          "bottom_right_y": 2.9281654,
+          "bottom_left_x": 2.9281654,
+          "bottom_left_y": 2.9281654
+        },
+        {
+          "top_left_x": 1.057313,
+          "top_left_y": 1.057313,
+          "top_right_x": 1.057313,
+          "top_right_y": 1.057313,
+          "bottom_right_x": 2.114626,
+          "bottom_right_y": 2.114626,
+          "bottom_left_x": 2.114626,
+          "bottom_left_y": 2.114626
+        },
+        {
+          "top_left_x": 0.7824335,
+          "top_left_y": 0.7824335,
+          "top_right_x": 0.7824335,
+          "top_right_y": 0.7824335,
+          "bottom_right_x": 1.564867,
+          "bottom_right_y": 1.564867,
+          "bottom_left_x": 1.564867,
+          "bottom_left_y": 1.564867
+        },
+        {
+          "top_left_x": 0.5863056,
+          "top_left_y": 0.5863056,
+          "top_right_x": 0.5863056,
+          "top_right_y": 0.5863056,
+          "bottom_right_x": 1.1726112,
+          "bottom_right_y": 1.1726112,
+          "bottom_left_x": 1.1726112,
+          "bottom_left_y": 1.1726112
+        },
+        {
+          "top_left_x": 0.4332962,
+          "top_left_y": 0.4332962,
+          "top_right_x": 0.4332962,
+          "top_right_y": 0.4332962,
+          "bottom_right_x": 0.8665924,
+          "bottom_right_y": 0.8665924,
+          "bottom_left_x": 0.8665924,
+          "bottom_left_y": 0.8665924
+        },
+        {
+          "top_left_x": 0.3145876,
+          "top_left_y": 0.3145876,
+          "top_right_x": 0.3145876,
+          "top_right_y": 0.3145876,
+          "bottom_right_x": 0.6291752,
+          "bottom_right_y": 0.6291752,
+          "bottom_left_x": 0.6291752,
+          "bottom_left_y": 0.6291752
+        },
+        {
+          "top_left_x": 0.22506618,
+          "top_left_y": 0.22506618,
+          "top_right_x": 0.22506618,
+          "top_right_y": 0.22506618,
+          "bottom_right_x": 0.45013237,
+          "bottom_right_y": 0.45013237,
+          "bottom_left_x": 0.45013237,
+          "bottom_left_y": 0.45013237
+        },
+        {
+          "top_left_x": 0.15591621,
+          "top_left_y": 0.15591621,
+          "top_right_x": 0.15591621,
+          "top_right_y": 0.15591621,
+          "bottom_right_x": 0.31183243,
+          "bottom_right_y": 0.31183243,
+          "bottom_left_x": 0.31183243,
+          "bottom_left_y": 0.31183243
+        },
+        {
+          "top_left_x": 0.100948334,
+          "top_left_y": 0.100948334,
+          "top_right_x": 0.100948334,
+          "top_right_y": 0.100948334,
+          "bottom_right_x": 0.20189667,
+          "bottom_right_y": 0.20189667,
+          "bottom_left_x": 0.20189667,
+          "bottom_left_y": 0.20189667
+        },
+        {
+          "top_left_x": 0.06496239,
+          "top_left_y": 0.06496239,
+          "top_right_x": 0.06496239,
+          "top_right_y": 0.06496239,
+          "bottom_right_x": 0.12992477,
+          "bottom_right_y": 0.12992477,
+          "bottom_left_x": 0.12992477,
+          "bottom_left_y": 0.12992477
+        },
+        {
+          "top_left_x": 0.03526497,
+          "top_left_y": 0.03526497,
+          "top_right_x": 0.03526497,
+          "top_right_y": 0.03526497,
+          "bottom_right_x": 0.07052994,
+          "bottom_right_y": 0.07052994,
+          "bottom_left_x": 0.07052994,
+          "bottom_left_y": 0.07052994
+        },
+        {
+          "top_left_x": 0.014661789,
+          "top_left_y": 0.014661789,
+          "top_right_x": 0.014661789,
+          "top_right_y": 0.014661789,
+          "bottom_right_x": 0.029323578,
+          "bottom_right_y": 0.029323578,
+          "bottom_left_x": 0.029323578,
+          "bottom_left_y": 0.029323578
+        },
+        {
+          "top_left_x": 0.0041856766,
+          "top_left_y": 0.0041856766,
+          "top_right_x": 0.0041856766,
+          "top_right_y": 0.0041856766,
+          "bottom_right_x": 0.008371353,
+          "bottom_right_y": 0.008371353,
+          "bottom_left_x": 0.008371353,
+          "bottom_left_y": 0.008371353
+        },
+        {
+          "top_left_x": 0,
+          "top_left_y": 0,
+          "top_right_x": 0,
+          "top_right_y": 0,
+          "bottom_right_x": 0,
+          "bottom_right_y": 0,
+          "bottom_left_x": 0,
+          "bottom_left_y": 0
+        }
+      ]
+    },
+    {
+      "name": "alpha",
+      "type": "int",
+      "data_points": [
+        0,
+        0,
+        115,
+        178,
+        217,
+        241,
+        253,
+        239,
+        183,
+        135,
+        91,
+        53,
+        23,
+        5,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
index 75a49d7..41974f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt
@@ -246,6 +246,8 @@
  */
 private class TestTransitionAnimatorController(override var transitionContainer: ViewGroup) :
     ActivityTransitionAnimator.Controller {
+    override val isLaunching: Boolean = true
+
     override fun createAnimatorState() =
         TransitionAnimator.State(
             top = 100,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt
new file mode 100644
index 0000000..c380a51
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt
@@ -0,0 +1,193 @@
+/*
+ * 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.animation
+
+import android.animation.AnimatorSet
+import android.graphics.drawable.GradientDrawable
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.activity.EmptyTestActivity
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import platform.test.motion.RecordedMotion
+import platform.test.motion.Sampling.Companion.evenlySampled
+import platform.test.motion.view.DrawableFeatureCaptures
+import platform.test.motion.view.ViewMotionTestRule
+import platform.test.screenshot.DeviceEmulationRule
+import platform.test.screenshot.DeviceEmulationSpec
+import platform.test.screenshot.DisplaySpec
+import platform.test.screenshot.GoldenPathManager
+import platform.test.screenshot.PathConfig
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class TransitionAnimatorTest : SysuiTestCase() {
+    companion object {
+        private const val GOLDENS_PATH = "frameworks/base/packages/SystemUI/tests/goldens"
+
+        private val emulationSpec =
+            DeviceEmulationSpec(
+                DisplaySpec(
+                    "phone",
+                    width = 320,
+                    height = 690,
+                    densityDpi = 160,
+                )
+            )
+    }
+
+    private val pathManager = GoldenPathManager(context, GOLDENS_PATH, pathConfig = PathConfig())
+    private val transitionAnimator =
+        TransitionAnimator(
+            ActivityTransitionAnimator.TIMINGS,
+            ActivityTransitionAnimator.INTERPOLATORS
+        )
+
+    @get:Rule(order = 0) val deviceEmulationRule = DeviceEmulationRule(emulationSpec)
+    @get:Rule(order = 1) val activityRule = ActivityScenarioRule(EmptyTestActivity::class.java)
+    @get:Rule(order = 2)
+    val motionRule =
+        ViewMotionTestRule<EmptyTestActivity>(
+            pathManager,
+            { activityRule.scenario },
+            context = context,
+            bitmapDiffer = null,
+        )
+
+    @Test
+    fun backgroundAnimation_whenLaunching() {
+        val backgroundLayer = GradientDrawable().apply { alpha = 0 }
+        val animator = setUpTest(backgroundLayer, isLaunching = true)
+
+        val recordedMotion = recordMotion(backgroundLayer, animator)
+
+        motionRule.assertThat(recordedMotion).timeSeriesMatchesGolden()
+    }
+
+    @Test
+    fun backgroundAnimation_whenReturning() {
+        val backgroundLayer = GradientDrawable().apply { alpha = 0 }
+        val animator = setUpTest(backgroundLayer, isLaunching = false)
+
+        val recordedMotion = recordMotion(backgroundLayer, animator)
+
+        motionRule.assertThat(recordedMotion).timeSeriesMatchesGolden()
+    }
+
+    @Test
+    fun backgroundAnimationWithoutFade_whenLaunching() {
+        val backgroundLayer = GradientDrawable().apply { alpha = 0 }
+        val animator =
+            setUpTest(backgroundLayer, isLaunching = true, fadeWindowBackgroundLayer = false)
+
+        val recordedMotion = recordMotion(backgroundLayer, animator)
+
+        motionRule.assertThat(recordedMotion).timeSeriesMatchesGolden()
+    }
+
+    @Test
+    fun backgroundAnimationWithoutFade_whenReturning() {
+        val backgroundLayer = GradientDrawable().apply { alpha = 0 }
+        val animator =
+            setUpTest(backgroundLayer, isLaunching = false, fadeWindowBackgroundLayer = false)
+
+        val recordedMotion = recordMotion(backgroundLayer, animator)
+
+        motionRule.assertThat(recordedMotion).timeSeriesMatchesGolden()
+    }
+
+    private fun setUpTest(
+        backgroundLayer: GradientDrawable,
+        isLaunching: Boolean,
+        fadeWindowBackgroundLayer: Boolean = true,
+    ): AnimatorSet {
+        lateinit var transitionContainer: ViewGroup
+        activityRule.scenario.onActivity { activity ->
+            transitionContainer = FrameLayout(activity).apply { setBackgroundColor(0x00FF00) }
+            activity.setContentView(transitionContainer)
+        }
+        waitForIdleSync()
+
+        val controller = TestController(transitionContainer, isLaunching)
+        val animator =
+            transitionAnimator.createAnimator(
+                controller,
+                createEndState(transitionContainer),
+                backgroundLayer,
+                fadeWindowBackgroundLayer
+            )
+        return AnimatorSet().apply {
+            duration = animator.duration
+            play(animator)
+        }
+    }
+
+    private fun createEndState(container: ViewGroup): TransitionAnimator.State {
+        val containerLocation = IntArray(2)
+        container.getLocationOnScreen(containerLocation)
+        return TransitionAnimator.State(
+            left = containerLocation[0],
+            top = containerLocation[1],
+            right = containerLocation[0] + emulationSpec.display.width,
+            bottom = containerLocation[1] + emulationSpec.display.height,
+            topCornerRadius = 0f,
+            bottomCornerRadius = 0f
+        )
+    }
+
+    private fun recordMotion(
+        backgroundLayer: GradientDrawable,
+        animator: AnimatorSet
+    ): RecordedMotion {
+        return motionRule.checkThat(animator).record(
+            backgroundLayer,
+            evenlySampled(20),
+            visualCapture = null
+        ) {
+            capture(DrawableFeatureCaptures.bounds, "bounds")
+            capture(DrawableFeatureCaptures.cornerRadii, "corner_radii")
+            capture(DrawableFeatureCaptures.alpha, "alpha")
+        }
+    }
+}
+
+/**
+ * A simple implementation of [TransitionAnimator.Controller] which throws if it is called outside
+ * of the main thread.
+ */
+private class TestController(
+    override var transitionContainer: ViewGroup,
+    override val isLaunching: Boolean
+) : TransitionAnimator.Controller {
+    override fun createAnimatorState(): TransitionAnimator.State {
+        val containerLocation = IntArray(2)
+        transitionContainer.getLocationOnScreen(containerLocation)
+        return TransitionAnimator.State(
+            left = containerLocation[0] + 100,
+            top = containerLocation[1] + 300,
+            right = containerLocation[0] + 200,
+            bottom = containerLocation[1] + 400,
+            topCornerRadius = 10f,
+            bottomCornerRadius = 20f
+        )
+    }
+}