Fix animation of UMO on long press

Flag: None
Bug: 286142657
Test: Checked the animation of UMO using animation scale x5.
Change-Id: Ia81b0d9a31cd94574dd51b083dd99146f9ff9b1e
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
index 1ec43c5..d277f32 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
@@ -60,7 +60,7 @@
     }
 
     companion object {
-        @JvmField val GUTS_ANIMATION_DURATION = 500L
+        @JvmField val GUTS_ANIMATION_DURATION = 234L
     }
 
     /** A listener when the current dimensions of the player change */
@@ -234,7 +234,8 @@
             currentStartLocation,
             currentEndLocation,
             currentTransitionProgress,
-            applyImmediately = false
+            applyImmediately = false,
+            isGutsAnimation = true,
         )
     }
 
@@ -254,7 +255,8 @@
             currentStartLocation,
             currentEndLocation,
             currentTransitionProgress,
-            applyImmediately = immediate
+            applyImmediately = immediate,
+            isGutsAnimation = true,
         )
     }
 
@@ -414,7 +416,10 @@
      * it's not available, it will recreate one by measuring, which may be expensive.
      */
     @VisibleForTesting
-    fun obtainViewState(state: MediaHostState?): TransitionViewState? {
+    fun obtainViewState(
+        state: MediaHostState?,
+        isGutsAnimation: Boolean = false
+    ): TransitionViewState? {
         if (state == null || state.measurementInput == null) {
             return null
         }
@@ -423,7 +428,7 @@
         val viewState = viewStates[cacheKey]
         if (viewState != null) {
             // we already have cached this measurement, let's continue
-            if (state.squishFraction <= 1f) {
+            if (state.squishFraction <= 1f && !isGutsAnimation) {
                 return squishViewState(viewState, state.squishFraction)
             }
             return viewState
@@ -455,13 +460,14 @@
 
             // Given that we have a measurement and a view, let's get (guaranteed) viewstates
             // from the start and end state and interpolate them
-            val startViewState = obtainViewState(startState) as TransitionViewState
+            val startViewState = obtainViewState(startState, isGutsAnimation) as TransitionViewState
             val endState = state.copy().also { it.expansion = 1.0f }
-            val endViewState = obtainViewState(endState) as TransitionViewState
+            val endViewState = obtainViewState(endState, isGutsAnimation) as TransitionViewState
             result =
                 layoutController.getInterpolatedState(startViewState, endViewState, state.expansion)
         }
-        if (state.squishFraction <= 1f) {
+        // Skip the adjustments of squish view state if UMO changes due to guts animation.
+        if (state.squishFraction <= 1f && !isGutsAnimation) {
             return squishViewState(result, state.squishFraction)
         }
         return result
@@ -521,7 +527,8 @@
         @MediaLocation startLocation: Int,
         @MediaLocation endLocation: Int,
         transitionProgress: Float,
-        applyImmediately: Boolean
+        applyImmediately: Boolean,
+        isGutsAnimation: Boolean = false,
     ) =
         traceSection("MediaViewController#setCurrentState") {
             currentEndLocation = endLocation
@@ -537,7 +544,7 @@
             // Obtain the view state that we'd want to be at the end
             // The view might not be bound yet or has never been measured and in that case will be
             // reset once the state is fully available
-            var endViewState = obtainViewState(endHostState) ?: return
+            var endViewState = obtainViewState(endHostState, isGutsAnimation) ?: return
             endViewState = updateViewStateSize(endViewState, endLocation, tmpState2)!!
             layoutController.setMeasureState(endViewState)
 
@@ -548,7 +555,7 @@
             }
 
             val result: TransitionViewState
-            var startViewState = obtainViewState(startHostState)
+            var startViewState = obtainViewState(startHostState, isGutsAnimation)
             startViewState = updateViewStateSize(startViewState, startLocation, tmpState3)
 
             if (!endHostState.visible) {
@@ -602,7 +609,8 @@
                 applyImmediately,
                 shouldAnimate,
                 animationDuration,
-                animationDelay
+                animationDelay,
+                isGutsAnimation,
             )
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
index db4ab7e..5b91615 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
@@ -25,6 +25,16 @@
  * The fraction after which we start fading in when going from a gone widget to a visible one
  */
 private const val GONE_FADE_FRACTION = 0.8f
+/**
+ * The fraction after which we start fading in going from a gone widget to a visible one in guts
+ * animation.
+ */
+private const val GONE_FADE_GUTS_FRACTION = 0.286f
+/**
+ * The fraction before which we fade out when going from a visible widget to a gone one in guts
+ * animation.
+ */
+private const val VISIBLE_FADE_GUTS_FRACTION = 0.355f
 
 /**
  * The amont we're scaling appearing views
@@ -45,6 +55,7 @@
     private var animationStartState: TransitionViewState? = null
     private var state = TransitionViewState()
     private var animator: ValueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f)
+    private var isGutsAnimation = false
     private var currentHeight: Int = 0
     private var currentWidth: Int = 0
     var sizeChangedListener: ((Int, Int) -> Unit)? = null
@@ -152,15 +163,6 @@
                 // this looks quite ugly
                 val nowGone: Boolean
                 if (widgetStart.gone) {
-
-                    // Only fade it in at the very end
-                    alphaProgress = MathUtils.map(GONE_FADE_FRACTION, 1.0f, 0.0f, 1.0f, progress)
-                    nowGone = progress < GONE_FADE_FRACTION
-
-                    // Scale it just a little, not all the way
-                    val endScale = widgetEnd.scale
-                    newScale = MathUtils.lerp(GONE_SCALE_AMOUNT * endScale, endScale, progress)
-
                     // don't clip
                     widthProgress = 1.0f
 
@@ -168,25 +170,52 @@
                     resultMeasureWidth = widgetEnd.measureWidth
                     resultMeasureHeight = widgetEnd.measureHeight
 
-                    // Let's make sure we're centering the view in the gone view instead of having
-                    // the left at 0
-                    resultX = MathUtils.lerp(widgetStart.x - resultMeasureWidth / 2.0f,
-                            widgetEnd.x,
-                            progress)
-                    resultY = MathUtils.lerp(widgetStart.y - resultMeasureHeight / 2.0f,
-                            widgetEnd.y,
-                            progress)
+                    if (isGutsAnimation) {
+                        // if animation is open/close guts, fade in starts early.
+                        alphaProgress = MathUtils.map(
+                            GONE_FADE_GUTS_FRACTION,
+                            1.0f,
+                            0.0f,
+                            1.0f,
+                            progress
+                        )
+                        nowGone = progress < GONE_FADE_GUTS_FRACTION
+
+                        // Do not change scale of widget.
+                        newScale = 1.0f
+
+                        // We do not want any horizontal or vertical movement.
+                        resultX = widgetStart.x
+                        resultY = widgetStart.y
+                    } else {
+                        // Only fade it in at the very end
+                        alphaProgress = MathUtils.map(
+                            GONE_FADE_FRACTION,
+                            1.0f,
+                            0.0f,
+                            1.0f,
+                            progress
+                        )
+                        nowGone = progress < GONE_FADE_FRACTION
+
+                        // Scale it just a little, not all the way
+                        val endScale = widgetEnd.scale
+                        newScale = MathUtils.lerp(GONE_SCALE_AMOUNT * endScale, endScale, progress)
+
+                        // Let's make sure we're centering the view in the gone view instead of
+                        // having the left at 0
+                        resultX = MathUtils.lerp(
+                                widgetStart.x - resultMeasureWidth / 2.0f,
+                                widgetEnd.x,
+                                progress
+                        )
+                        resultY = MathUtils.lerp(
+                                widgetStart.y - resultMeasureHeight / 2.0f,
+                                widgetEnd.y,
+                                progress
+                        )
+                    }
                 } else {
-
-                    // Fadeout in the very beginning
-                    alphaProgress = MathUtils.map(0.0f, 1.0f - GONE_FADE_FRACTION, 0.0f, 1.0f,
-                            progress)
-                    nowGone = progress > 1.0f - GONE_FADE_FRACTION
-
-                    // Scale it just a little, not all the way
-                    val startScale = widgetStart.scale
-                    newScale = MathUtils.lerp(startScale, startScale * GONE_SCALE_AMOUNT, progress)
-
                     // Don't clip
                     widthProgress = 0.0f
 
@@ -194,14 +223,54 @@
                     resultMeasureWidth = widgetStart.measureWidth
                     resultMeasureHeight = widgetStart.measureHeight
 
-                    // Let's make sure we're centering the view in the gone view instead of having
-                    // the left at 0
-                    resultX = MathUtils.lerp(widgetStart.x,
-                            widgetEnd.x - resultMeasureWidth / 2.0f,
-                            progress)
-                    resultY = MathUtils.lerp(widgetStart.y,
-                            widgetEnd.y - resultMeasureHeight / 2.0f,
-                            progress)
+                    // Fadeout in the very beginning
+                    if (isGutsAnimation) {
+                        alphaProgress = MathUtils.map(
+                            0.0f,
+                            VISIBLE_FADE_GUTS_FRACTION,
+                            0.0f,
+                            1.0f,
+                            progress
+                        )
+                        nowGone = progress > VISIBLE_FADE_GUTS_FRACTION
+
+                        // Do not change scale of widget during open/close guts animation.
+                        newScale = 1.0f
+
+                        // We do not want any horizontal or vertical movement.
+                        resultX = widgetEnd.x
+                        resultY = widgetEnd.y
+                    } else {
+                        alphaProgress = MathUtils.map(
+                            0.0f,
+                            1.0f - GONE_FADE_FRACTION,
+                            0.0f,
+                            1.0f,
+                            progress
+                        )
+                        nowGone = progress > 1.0f - GONE_FADE_FRACTION
+
+                        // Scale it just a little, not all the way
+                        val startScale = widgetStart.scale
+                        newScale = MathUtils.lerp(
+                                startScale,
+                                startScale * GONE_SCALE_AMOUNT,
+                                progress
+                        )
+
+                        // Let's make sure we're centering the view in the gone view instead of
+                        // having the left at 0
+                        resultX = MathUtils.lerp(
+                                widgetStart.x,
+                                widgetEnd.x - resultMeasureWidth / 2.0f,
+                                progress
+                        )
+                        resultY = MathUtils.lerp(
+                                widgetStart.y,
+                                widgetEnd.y - resultMeasureHeight / 2.0f,
+                                progress
+                        )
+                    }
                 }
                 resultWidgetState.gone = nowGone
             } else {
@@ -279,8 +348,10 @@
         applyImmediately: Boolean,
         animate: Boolean,
         duration: Long = 0,
-        delay: Long = 0
+        delay: Long = 0,
+        isGuts: Boolean,
     ) {
+        isGutsAnimation = isGuts
         val animated = animate && currentState.width != 0
         this.state = state.copy()
         if (applyImmediately || transitionLayout == null) {
@@ -291,6 +362,8 @@
             animationStartState = currentState.copy()
             animator.duration = duration
             animator.startDelay = delay
+            animator.interpolator =
+                if (isGutsAnimation) Interpolators.LINEAR else Interpolators.FAST_OUT_SLOW_IN
             animator.start()
         } else if (!animator.isRunning) {
             applyStateToLayout(this.state)