Update smartspace visibility to correct target during clock size transition

Sometimes ClockSizeTransition is given the wrong target visibility for
smartspace date/weather view. This causes it override the correct value
when it comes in later. To correct this, we ensure we're animating to
the correct target value every frame.

This may cause animation hiccups in some edge-cases, including the case
that's being fixed, but it corrected fast enough that it wasn't visible
in my testing.

Bug: 376075102
Flag: NONE Bugfix
Test: Manually checked reproduction
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:7fe71e59ed00a9da86c5b59dc9c2428b69199529)
Merged-In: I5bfd754c82c15759348a2ecf8ba94a133f2d547b
Change-Id: I5bfd754c82c15759348a2ecf8ba94a133f2d547b
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
index a595d81..29bda76 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt
@@ -86,15 +86,56 @@
             transition.values[SMARTSPACE_BOUNDS] = targetSSView.getRect()
         }
 
-        open fun mutateBounds(
-            view: View,
-            fromIsVis: Boolean,
-            toIsVis: Boolean,
-            fromBounds: Rect,
-            toBounds: Rect,
-            fromSSBounds: Rect?,
-            toSSBounds: Rect?,
-        ) {}
+        open fun initTargets(from: Target, to: Target) {}
+
+        open fun mutateTargets(from: Target, to: Target) {}
+
+        data class Target(
+            var view: View,
+            var visibility: Int,
+            var isVisible: Boolean,
+            var alpha: Float,
+            var bounds: Rect,
+            var ssBounds: Rect?,
+        ) {
+            companion object {
+                fun fromStart(startValues: TransitionValues): Target {
+                    var fromVis = startValues.values[PROP_VISIBILITY] as Int
+                    var fromIsVis = fromVis == View.VISIBLE
+                    var fromAlpha = startValues.values[PROP_ALPHA] as Float
+
+                    // Align starting visibility and alpha
+                    if (!fromIsVis) fromAlpha = 0f
+                    else if (fromAlpha <= 0f) {
+                        fromIsVis = false
+                        fromVis = View.INVISIBLE
+                    }
+
+                    return Target(
+                        view = startValues.view,
+                        visibility = fromVis,
+                        isVisible = fromIsVis,
+                        alpha = fromAlpha,
+                        bounds = startValues.values[PROP_BOUNDS] as Rect,
+                        ssBounds = startValues.values[SMARTSPACE_BOUNDS] as Rect?,
+                    )
+                }
+
+                fun fromEnd(endValues: TransitionValues): Target {
+                    val toVis = endValues.values[PROP_VISIBILITY] as Int
+                    val toIsVis = toVis == View.VISIBLE
+
+                    return Target(
+                        view = endValues.view,
+                        visibility = toVis,
+                        isVisible = toIsVis,
+                        alpha = if (toIsVis) 1f else 0f,
+                        bounds = endValues.values[PROP_BOUNDS] as Rect,
+                        ssBounds = endValues.values[SMARTSPACE_BOUNDS] as Rect?,
+                    )
+                }
+            }
+        }
 
         override fun createAnimator(
             sceenRoot: ViewGroup,
@@ -109,72 +150,58 @@
                 return null
             }
 
-            var fromVis = startValues.values[PROP_VISIBILITY] as Int
-            var fromIsVis = fromVis == View.VISIBLE
-            var fromAlpha = startValues.values[PROP_ALPHA] as Float
-            val fromBounds = startValues.values[PROP_BOUNDS] as Rect
-            val fromSSBounds = startValues.values[SMARTSPACE_BOUNDS] as Rect?
+            val from = Target.fromStart(startValues)
+            val to = Target.fromEnd(endValues)
+            initTargets(from, to)
+            mutateTargets(from, to)
 
-            val toView = endValues.view
-            val toVis = endValues.values[PROP_VISIBILITY] as Int
-            val toBounds = endValues.values[PROP_BOUNDS] as Rect
-            val toSSBounds = endValues.values[SMARTSPACE_BOUNDS] as Rect?
-            val toIsVis = toVis == View.VISIBLE
-            val toAlpha = if (toIsVis) 1f else 0f
-
-            // Align starting visibility and alpha
-            if (!fromIsVis) fromAlpha = 0f
-            else if (fromAlpha <= 0f) {
-                fromIsVis = false
-                fromVis = View.INVISIBLE
-            }
-
-            mutateBounds(toView, fromIsVis, toIsVis, fromBounds, toBounds, fromSSBounds, toSSBounds)
-            if (fromIsVis == toIsVis && fromBounds.equals(toBounds)) {
+            if (from.isVisible == to.isVisible && from.bounds.equals(to.bounds)) {
                 if (DEBUG) {
                     Log.w(
                         TAG,
-                        "Skipping no-op transition: $toView; " +
-                            "vis: $fromVis -> $toVis; " +
-                            "alpha: $fromAlpha -> $toAlpha; " +
-                            "bounds: $fromBounds -> $toBounds; ",
+                        "Skipping no-op transition: ${to.view}; " +
+                            "vis: ${from.visibility} -> ${to.visibility}; " +
+                            "alpha: ${from.alpha} -> ${to.alpha}; " +
+                            "bounds: ${from.bounds} -> ${to.bounds}; ",
                     )
                 }
                 return null
             }
 
-            val sendToBack = fromIsVis && !toIsVis
+            val sendToBack = from.isVisible && !to.isVisible
             fun lerp(start: Int, end: Int, fract: Float): Int =
                 MathUtils.lerp(start.toFloat(), end.toFloat(), fract).toInt()
             fun computeBounds(fract: Float): Rect =
                 Rect(
-                    lerp(fromBounds.left, toBounds.left, fract),
-                    lerp(fromBounds.top, toBounds.top, fract),
-                    lerp(fromBounds.right, toBounds.right, fract),
-                    lerp(fromBounds.bottom, toBounds.bottom, fract),
+                    lerp(from.bounds.left, to.bounds.left, fract),
+                    lerp(from.bounds.top, to.bounds.top, fract),
+                    lerp(from.bounds.right, to.bounds.right, fract),
+                    lerp(from.bounds.bottom, to.bounds.bottom, fract),
                 )
 
             fun assignAnimValues(src: String, fract: Float, vis: Int? = null) {
+                mutateTargets(from, to)
                 val bounds = computeBounds(fract)
-                val alpha = MathUtils.lerp(fromAlpha, toAlpha, fract)
+                val alpha = MathUtils.lerp(from.alpha, to.alpha, fract)
                 if (DEBUG) {
                     Log.i(
                         TAG,
-                        "$src: $toView; fract=$fract; alpha=$alpha; vis=$vis; bounds=$bounds;",
+                        "$src: ${to.view}; fract=$fract; alpha=$alpha; vis=$vis; bounds=$bounds;",
                     )
                 }
-                toView.setVisibility(vis ?: View.VISIBLE)
-                toView.setAlpha(alpha)
-                toView.setRect(bounds)
+
+                to.view.setVisibility(vis ?: View.VISIBLE)
+                to.view.setAlpha(alpha)
+                to.view.setRect(bounds)
             }
 
             if (DEBUG) {
                 Log.i(
                     TAG,
-                    "transitioning: $toView; " +
-                        "vis: $fromVis -> $toVis; " +
-                        "alpha: $fromAlpha -> $toAlpha; " +
-                        "bounds: $fromBounds -> $toBounds; ",
+                    "transitioning: ${to.view}; " +
+                        "vis: ${from.visibility} -> ${to.visibility}; " +
+                        "alpha: ${from.alpha} -> ${to.alpha}; " +
+                        "bounds: ${from.bounds} -> ${to.bounds}; ",
                 )
             }
 
@@ -190,11 +217,11 @@
                 this@VisibilityBoundsTransition.addListener(
                     object : TransitionListenerAdapter() {
                         override fun onTransitionStart(t: Transition) {
-                            toView.viewTreeObserver.addOnPreDrawListener(predrawCallback)
+                            to.view.viewTreeObserver.addOnPreDrawListener(predrawCallback)
                         }
 
                         override fun onTransitionEnd(t: Transition) {
-                            toView.viewTreeObserver.removeOnPreDrawListener(predrawCallback)
+                            to.view.viewTreeObserver.removeOnPreDrawListener(predrawCallback)
                         }
                     }
                 )
@@ -202,17 +229,17 @@
                 val listener =
                     object : AnimatorListenerAdapter() {
                         override fun onAnimationStart(anim: Animator) {
-                            assignAnimValues("start", 0f, fromVis)
+                            assignAnimValues("start", 0f, from.visibility)
                         }
 
                         override fun onAnimationEnd(anim: Animator) {
-                            assignAnimValues("end", 1f, toVis)
-                            if (sendToBack) toView.translationZ = 0f
+                            assignAnimValues("end", 1f, to.visibility)
+                            if (sendToBack) to.view.translationZ = 0f
                         }
                     }
 
                 anim.addListener(listener)
-                assignAnimValues("init", 0f, fromVis)
+                assignAnimValues("init", 0f, from.visibility)
             }
         }
 
@@ -251,31 +278,23 @@
             }
         }
 
-        override fun mutateBounds(
-            view: View,
-            fromIsVis: Boolean,
-            toIsVis: Boolean,
-            fromBounds: Rect,
-            toBounds: Rect,
-            fromSSBounds: Rect?,
-            toSSBounds: Rect?,
-        ) {
+        override fun initTargets(from: Target, to: Target) {
             // Move normally if clock is not changing visibility
-            if (fromIsVis == toIsVis) return
+            if (from.isVisible == to.isVisible) return
 
-            fromBounds.set(toBounds)
+            from.bounds.set(to.bounds)
             if (isLargeClock) {
                 // Large clock shouldn't move; fromBounds already set
-            } else if (toSSBounds != null && fromSSBounds != null) {
+            } else if (to.ssBounds != null && from.ssBounds != null) {
                 // Instead of moving the small clock the full distance, we compute the distance
                 // smartspace will move. We then scale this to match the duration of this animation
                 // so that the small clock moves at the same speed as smartspace.
                 val ssTranslation =
-                    abs((toSSBounds.top - fromSSBounds.top) * smallClockMoveScale).toInt()
-                fromBounds.top = toBounds.top - ssTranslation
-                fromBounds.bottom = toBounds.bottom - ssTranslation
+                    abs((to.ssBounds!!.top - from.ssBounds!!.top) * smallClockMoveScale).toInt()
+                from.bounds.top = to.bounds.top - ssTranslation
+                from.bounds.bottom = to.bounds.bottom - ssTranslation
             } else {
-                Log.e(TAG, "mutateBounds: smallClock received no smartspace bounds")
+                Log.e(TAG, "initTargets: smallClock received no smartspace bounds")
             }
         }
     }
@@ -320,10 +339,9 @@
         }
     }
 
-    // TODO: Might need a mechanism to update this one while in-progress
     class SmartspaceMoveTransition(
         val config: IntraBlueprintTransition.Config,
-        viewModel: KeyguardClockViewModel,
+        val viewModel: KeyguardClockViewModel,
     ) : VisibilityBoundsTransition() {
         private val isLargeClock = viewModel.isLargeClockVisible.value
         override val captureSmartspace = false
@@ -340,23 +358,23 @@
             addTarget(R.id.status_view_media_container)
         }
 
-        override fun mutateBounds(
-            view: View,
-            fromIsVis: Boolean,
-            toIsVis: Boolean,
-            fromBounds: Rect,
-            toBounds: Rect,
-            fromSSBounds: Rect?,
-            toSSBounds: Rect?,
-        ) {
+        override fun initTargets(from: Target, to: Target) {
             // If view is changing visibility, hold it in place
-            if (fromIsVis == toIsVis) return
-            if (DEBUG) Log.i(TAG, "Holding position of ${view.id}")
+            if (from.isVisible == to.isVisible) return
+            if (DEBUG) Log.i(TAG, "Holding position of ${to.view.id}")
 
-            if (fromIsVis) {
-                toBounds.set(fromBounds)
+            if (from.isVisible) {
+                to.bounds.set(from.bounds)
             } else {
-                fromBounds.set(toBounds)
+                from.bounds.set(to.bounds)
+            }
+        }
+
+        override fun mutateTargets(from: Target, to: Target) {
+            if (to.view.id == sharedR.id.date_smartspace_view) {
+                to.isVisible = !viewModel.hasCustomWeatherDataDisplay.value
+                to.visibility = if (to.isVisible) View.VISIBLE else View.GONE
+                to.alpha = if (to.isVisible) 1f else 0f
             }
         }