Merge "Fix flicker when starting folding" into tm-qpr-dev
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 2334a4c..9421524 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -90,8 +90,13 @@
 class LinearLightRevealEffect(private val isVertical: Boolean) : LightRevealEffect {
 
     // Interpolator that reveals >80% of the content at 0.5 progress, makes revealing faster
-    private val interpolator = PathInterpolator(/* controlX1= */ 0.4f, /* controlY1= */ 0f,
-            /* controlX2= */ 0.2f, /* controlY2= */ 1f)
+    private val interpolator =
+        PathInterpolator(
+            /* controlX1= */ 0.4f,
+            /* controlY1= */ 0f,
+            /* controlX2= */ 0.2f,
+            /* controlY2= */ 1f
+        )
 
     override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
         val interpolatedAmount = interpolator.getInterpolation(amount)
@@ -116,17 +121,17 @@
 
         if (isVertical) {
             scrim.setRevealGradientBounds(
-                left = scrim.width / 2 - (scrim.width / 2) * gradientBoundsAmount,
+                left = scrim.viewWidth / 2 - (scrim.viewWidth / 2) * gradientBoundsAmount,
                 top = 0f,
-                right = scrim.width / 2 + (scrim.width / 2) * gradientBoundsAmount,
-                bottom = scrim.height.toFloat()
+                right = scrim.viewWidth / 2 + (scrim.viewWidth / 2) * gradientBoundsAmount,
+                bottom = scrim.viewHeight.toFloat()
             )
         } else {
             scrim.setRevealGradientBounds(
                 left = 0f,
-                top = scrim.height / 2 - (scrim.height / 2) * gradientBoundsAmount,
-                right = scrim.width.toFloat(),
-                bottom = scrim.height / 2 + (scrim.height / 2) * gradientBoundsAmount
+                top = scrim.viewHeight / 2 - (scrim.viewHeight / 2) * gradientBoundsAmount,
+                right = scrim.viewWidth.toFloat(),
+                bottom = scrim.viewHeight / 2 + (scrim.viewHeight / 2) * gradientBoundsAmount
             )
         }
     }
@@ -234,7 +239,14 @@
  * transparent center. The center position, size, and stops of the gradient can be manipulated to
  * reveal views below the scrim as if they are being 'lit up'.
  */
-class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
+class LightRevealScrim
+@JvmOverloads
+constructor(
+    context: Context?,
+    attrs: AttributeSet?,
+    initialWidth: Int? = null,
+    initialHeight: Int? = null
+) : View(context, attrs) {
 
     /** Listener that is called if the scrim's opaqueness changes */
     lateinit var isScrimOpaqueChangedListener: Consumer<Boolean>
@@ -278,6 +290,17 @@
     var revealGradientHeight: Float = 0f
 
     /**
+     * Keeps the initial value until the view is measured. See [LightRevealScrim.onMeasure].
+     *
+     * Needed as the view dimensions are used before the onMeasure pass happens, and without preset
+     * width and height some flicker during fold/unfold happens.
+     */
+    internal var viewWidth: Int = initialWidth ?: 0
+        private set
+    internal var viewHeight: Int = initialHeight ?: 0
+        private set
+
+    /**
      * Alpha of the fill that can be used in the beginning of the animation to hide the content.
      * Normally the gradient bounds are animated from small size so the content is not visible, but
      * if the start gradient bounds allow to see some content this could be used to make the reveal
@@ -375,6 +398,11 @@
         invalidate()
     }
 
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+        viewWidth = measuredWidth
+        viewHeight = measuredHeight
+    }
     /**
      * Sets bounds for the transparent oval gradient that reveals the views below the scrim. This is
      * simply a helper method that sets [revealGradientCenter], [revealGradientWidth], and
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
index 9cca950..523cf68 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
@@ -159,18 +159,24 @@
         ensureOverlayRemoved()
 
         val newRoot = SurfaceControlViewHost(context, context.display!!, wwm)
-        val newView =
-            LightRevealScrim(context, null).apply {
-                revealEffect = createLightRevealEffect()
-                isScrimOpaqueChangedListener = Consumer {}
-                revealAmount =
-                    when (reason) {
-                        FOLD -> TRANSPARENT
-                        UNFOLD -> BLACK
-                    }
-            }
-
         val params = getLayoutParams()
+        val newView =
+            LightRevealScrim(
+                    context,
+                    attrs = null,
+                    initialWidth = params.width,
+                    initialHeight = params.height
+                )
+                .apply {
+                    revealEffect = createLightRevealEffect()
+                    isScrimOpaqueChangedListener = Consumer {}
+                    revealAmount =
+                        when (reason) {
+                            FOLD -> TRANSPARENT
+                            UNFOLD -> BLACK
+                        }
+                }
+
         newRoot.setView(newView, params)
 
         if (onOverlayReady != null) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt
index 97fe25d..d3befb4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt
@@ -20,6 +20,7 @@
 import android.view.View
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
 import org.junit.Before
@@ -36,7 +37,7 @@
 
   @Before
   fun setUp() {
-    scrim = LightRevealScrim(context, null)
+    scrim = LightRevealScrim(context, null, DEFAULT_WIDTH, DEFAULT_HEIGHT)
     scrim.isScrimOpaqueChangedListener = Consumer { opaque ->
       isOpaque = opaque
     }
@@ -63,4 +64,25 @@
     scrim.revealAmount = 0.5f
     assertFalse("Scrim is opaque even though it's revealed", scrim.isScrimOpaque)
   }
+
+  @Test
+  fun testBeforeOnMeasure_defaultDimensions() {
+    assertThat(scrim.viewWidth).isEqualTo(DEFAULT_WIDTH)
+    assertThat(scrim.viewHeight).isEqualTo(DEFAULT_HEIGHT)
+  }
+
+  @Test
+  fun testAfterOnMeasure_measuredDimensions() {
+    scrim.measure(/* widthMeasureSpec= */ exact(1), /* heightMeasureSpec= */ exact(2))
+
+    assertThat(scrim.viewWidth).isEqualTo(1)
+    assertThat(scrim.viewHeight).isEqualTo(2)
+  }
+
+  private fun exact(value: Int) = View.MeasureSpec.makeMeasureSpec(value, View.MeasureSpec.EXACTLY)
+
+  private companion object {
+    private const val DEFAULT_WIDTH = 42
+    private const val DEFAULT_HEIGHT = 24
+  }
 }
\ No newline at end of file