Fix flicker when starting folding
The dimensions of LightRevealScrim were used before the view was being measured, causing the entire screen to become black for one frame sometimes (especially after boot. Now, LightRevealScrim accepts the initial dimensions what are used before the view is measured. Bug: 261560634 Test: LightRevealScrimTest && many unfolds soon after rebooting Change-Id: I91d1f2de82c563f085c9565c6e7116abb1e43e1d
This commit is contained in:
@@ -90,8 +90,13 @@ object LiftReveal : LightRevealEffect {
|
||||
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 @@ class LinearLightRevealEffect(private val isVertical: Boolean) : LightRevealEffe
|
||||
|
||||
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 @@ class PowerButtonReveal(
|
||||
* 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>
|
||||
@@ -277,6 +289,17 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context,
|
||||
var revealGradientWidth: Float = 0f
|
||||
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
|
||||
@@ -375,6 +398,11 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context,
|
||||
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
|
||||
|
||||
@@ -159,18 +159,24 @@ constructor(
|
||||
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) {
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.testing.AndroidTestingRunner
|
||||
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 @@ class LightRevealScrimTest : SysuiTestCase() {
|
||||
|
||||
@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 @@ class LightRevealScrimTest : SysuiTestCase() {
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user