Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ec7af7f6 authored by Luca Zuccarini's avatar Luca Zuccarini
Browse files

Include INVISIBLE views in animations by the ViewHierarchyAnimator.

If we exclude them, they behave incorrectly as they fade in and out
while moving. They still take up space on screen while invisible, so they
should be animated along with the rest of the views.

Bug: 234337113
Test: included
Change-Id: Ifa31bd0b526a504b8f60ff8893d3d1caa673eb90
parent 9e76e357
Loading
Loading
Loading
Loading
+8 −8
Original line number Diff line number Diff line
@@ -106,7 +106,7 @@ class ViewHierarchyAnimator {
            ephemeral: Boolean
        ): Boolean {
            if (
                !isVisible(
                !occupiesSpace(
                    rootView.visibility,
                    rootView.left,
                    rootView.top,
@@ -177,7 +177,7 @@ class ViewHierarchyAnimator {
            fadeInInterpolator: Interpolator = DEFAULT_FADE_IN_INTERPOLATOR
        ): Boolean {
            if (
                isVisible(
                occupiesSpace(
                    rootView.visibility,
                    rootView.left,
                    rootView.top,
@@ -295,7 +295,7 @@ class ViewHierarchyAnimator {

                    (view.getTag(R.id.tag_animator) as? ObjectAnimator)?.cancel()

                    if (!isVisible(view.visibility, left, top, right, bottom)) {
                    if (!occupiesSpace(view.visibility, left, top, right, bottom)) {
                        setBound(view, Bound.LEFT, left)
                        setBound(view, Bound.TOP, top)
                        setBound(view, Bound.RIGHT, right)
@@ -362,7 +362,7 @@ class ViewHierarchyAnimator {
            duration: Long = DEFAULT_DURATION
        ): Boolean {
            if (
                !isVisible(
                !occupiesSpace(
                    rootView.visibility,
                    rootView.left,
                    rootView.top,
@@ -530,17 +530,17 @@ class ViewHierarchyAnimator {
        }

        /**
         * Returns whether the given [visibility] and bounds are consistent with a view being
         * currently visible on screen.
         * Returns whether the given [visibility] and bounds are consistent with a view being a
         * contributing part of the hierarchy.
         */
        private fun isVisible(
        private fun occupiesSpace(
            visibility: Int,
            left: Int,
            top: Int,
            right: Int,
            bottom: Int
        ): Boolean {
            return visibility == View.VISIBLE && left != right && top != bottom
            return visibility != View.GONE && left != right && top != bottom
        }

        /**
+18 −22
Original line number Diff line number Diff line
@@ -207,25 +207,30 @@ ViewHierarchyAnimatorTest : SysuiTestCase() {
    }

    @Test
    fun animatesAppearingViewsFromStartToEnd() {
        // Starting GONE.
        rootView.visibility = View.GONE
        rootView.layout(0 /* l */, 50 /* t */, 50 /* r */, 100 /* b */)
        var success = ViewHierarchyAnimator.animateAddition(rootView)
        rootView.visibility = View.VISIBLE
        rootView.layout(0 /* l */, 100 /* t */, 100 /* r */, 200 /* b */)
    fun animatesInvisibleViews() {
        rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
        rootView.visibility = View.INVISIBLE

        val success = ViewHierarchyAnimator.animate(rootView)
        // Change all bounds.
        rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */)

        assertTrue(success)
        assertNotNull(rootView.getTag(R.id.tag_animator))
        checkBounds(rootView, l = 50, t = 150, r = 50, b = 150)
        // The initial values should be those of the previous layout.
        checkBounds(rootView, l = 10, t = 10, r = 50, b = 50)
        endAnimation(rootView)
        assertNull(rootView.getTag(R.id.tag_animator))
        checkBounds(rootView, l = 0, t = 100, r = 100, b = 200)
        // The end values should be those of the latest layout.
        checkBounds(rootView, l = 0, t = 15, r = 70, b = 80)
    }

        // Starting INVISIBLE.
        rootView.visibility = View.INVISIBLE
    @Test
    fun animatesAppearingViewsFromStartToEnd() {
        // Starting GONE.
        rootView.visibility = View.GONE
        rootView.layout(0 /* l */, 50 /* t */, 50 /* r */, 100 /* b */)
        success = ViewHierarchyAnimator.animateAddition(rootView)
        var success = ViewHierarchyAnimator.animateAddition(rootView)
        rootView.visibility = View.VISIBLE
        rootView.layout(0 /* l */, 100 /* t */, 100 /* r */, 200 /* b */)

@@ -937,7 +942,7 @@ ViewHierarchyAnimatorTest : SysuiTestCase() {
    }

    @Test
    fun doesNotAnimateInvisibleViews() {
    fun doesNotAnimateGoneViews() {
        rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)

        // GONE
@@ -948,15 +953,6 @@ ViewHierarchyAnimatorTest : SysuiTestCase() {
        assertFalse(success)
        assertNull(rootView.getTag(R.id.tag_animator))
        checkBounds(rootView, l = 0, t = 15, r = 55, b = 80)

        // INVISIBLE.
        rootView.visibility = View.INVISIBLE
        success = ViewHierarchyAnimator.animate(rootView)
        rootView.layout(0 /* l */, 20 /* t */, 10 /* r */, 50 /* b */)

        assertFalse(success)
        assertNull(rootView.getTag(R.id.tag_animator))
        checkBounds(rootView, l = 0, t = 20, r = 10, b = 50)
    }

    @Test