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

Commit b540a9af authored by An An Yu's avatar An An Yu
Browse files

Remove clip adjustment to fix bottom screen flicker issue.

Add a flicker test to verify animation background is no longer
visible through the transition after the fix.

Test: atest
Bug: 284148123
Change-Id: Iae41b96f097a428c3eae0e827caa026154fccf3d
Merged-In: Iae41b96f097a428c3eae0e827caa026154fccf3d
parent cbbde14c
Loading
Loading
Loading
Loading
+2 −15
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ class ActivityEmbeddingAnimationAdapter {
    final SurfaceControl mLeash;
    /** Area in absolute coordinate that the animation surface shouldn't go beyond. */
    @NonNull
    private final Rect mWholeAnimationBounds = new Rect();
    final Rect mWholeAnimationBounds = new Rect();
    /**
     * Area in absolute coordinate that should represent all the content to show for this window.
     * This should be the end bounds for opening window, and start bounds for closing window in case
@@ -229,20 +229,7 @@ class ActivityEmbeddingAnimationAdapter {
            mTransformation.getMatrix().postTranslate(mContentRelOffset.x, mContentRelOffset.y);
            t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
            t.setAlpha(mLeash, mTransformation.getAlpha());

            // The following applies an inverse scale to the clip-rect so that it crops "after" the
            // scale instead of before.
            mVecs[1] = mVecs[2] = 0;
            mVecs[0] = mVecs[3] = 1;
            mTransformation.getMatrix().mapVectors(mVecs);
            mVecs[0] = 1.f / mVecs[0];
            mVecs[3] = 1.f / mVecs[3];
            final Rect clipRect = mTransformation.getClipRect();
            mRect.left = (int) (clipRect.left * mVecs[0] + 0.5f);
            mRect.right = (int) (clipRect.right * mVecs[0] + 0.5f);
            mRect.top = (int) (clipRect.top * mVecs[3] + 0.5f);
            mRect.bottom = (int) (clipRect.bottom * mVecs[3] + 0.5f);
            t.setCrop(mLeash, mRect);
            t.setWindowCrop(mLeash, mWholeAnimationBounds.width(), mWholeAnimationBounds.height());
        }
    }
}
+0 −9
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.ClipRectAnimation;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.ScaleAnimation;
@@ -189,14 +188,6 @@ class ActivityEmbeddingAnimationSpec {
                startBounds.top - endBounds.top, 0);
        endTranslate.setDuration(CHANGE_ANIMATION_DURATION);
        endSet.addAnimation(endTranslate);
        // The end leash is resizing, we should update the window crop based on the clip rect.
        final Rect startClip = new Rect(startBounds);
        final Rect endClip = new Rect(endBounds);
        startClip.offsetTo(0, 0);
        endClip.offsetTo(0, 0);
        final Animation clipAnim = new ClipRectAnimation(startClip, endClip);
        clipAnim.setDuration(CHANGE_ANIMATION_DURATION);
        endSet.addAnimation(clipAnim);
        endSet.initialize(startBounds.width(), startBounds.height(), parentBounds.width(),
                parentBounds.height());
        endSet.scaleCurrentDuration(mTransitionAnimationScaleSetting);
+13 −0
Original line number Diff line number Diff line
@@ -17,9 +17,12 @@
package com.android.server.wm.flicker.activityembedding

import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.platform.test.annotations.Presubmit
import android.tools.common.traces.component.ComponentNameMatcher
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.Before
import org.junit.Test

abstract class ActivityEmbeddingTestBase(flicker: LegacyFlickerTest) : BaseTest(flicker) {
    val testApp = ActivityEmbeddingAppHelper(instrumentation)
@@ -29,4 +32,14 @@ abstract class ActivityEmbeddingTestBase(flicker: LegacyFlickerTest) : BaseTest(
        // The test should only be run on devices that support ActivityEmbedding.
        ActivityEmbeddingAppHelper.assumeActivityEmbeddingSupportedDevice()
    }

    /** Asserts the background animation layer is never visible during bounds change transition. */
    @Presubmit
    @Test
    fun backgroundLayerNeverVisible() {
        val backgroundColorLayer = ComponentNameMatcher("", "Animation Background")
        flicker.assertLayers {
            isInvisible(backgroundColorLayer)
        }
    }
}
+152 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.wm.flicker.activityembedding

import android.platform.test.annotations.Presubmit
import android.tools.common.datatypes.Rect
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized

/**
 * Test changing split ratio at runtime on a horizona split.
 *
 * Setup: Launch A|B in horizontal split with B being the secondary activity, by default A and B
 * windows are equal in size. B is on the top and A is on the bottom.
 * Transitions:
 * Change the split ratio to A:B=0.7:0.3, expect bounds change for both A and B.
 *
 * To run this test: `atest FlickerTests:HorizontalSplitChangeRatioTest`
 */
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class HorizontalSplitChangeRatioTest(flicker: LegacyFlickerTest) :
        ActivityEmbeddingTestBase(flicker) {
    /** {@inheritDoc} */
    override val transition: FlickerBuilder.() -> Unit = {
        setup {
            tapl.setExpectedRotationCheckEnabled(false)
            testApp.launchViaIntent(wmHelper)
            testApp.launchSecondaryActivityHorizontally(wmHelper)
            startDisplayBounds =
                    wmHelper.currentState.layerState.physicalDisplayBounds
                            ?: error("Display not found")
        }
        transitions {
            testApp.changeSecondaryActivityRatio(wmHelper)
        }
        teardown {
            tapl.goHome()
            testApp.exit(wmHelper)
        }
    }

    /** Assert the Main activity window is always visible. */
    @Presubmit
    @Test
    fun mainActivityWindowIsAlwaysVisible() {
        flicker.assertWm { isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) }
    }

    /** Assert the Main activity window is always visible. */
    @Presubmit
    @Test
    fun mainActivityLayerIsAlwaysVisible() {
        flicker.assertLayers { isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) }
    }

    /** Assert the Secondary activity window is always visible. */
    @Presubmit
    @Test
    fun secondaryActivityWindowIsAlwaysVisible() {
        flicker.assertWm {
            isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT) }
    }

    /** Assert the Secondary activity window is always visible. */
    @Presubmit
    @Test
    fun secondaryActivityLayerIsAlwaysVisible() {
        flicker.assertLayers { isVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT) }
    }

    /** Assert the Main and Secondary activity change height during the transition. */
    @Presubmit
    @Test
    fun secondaryActivityAdjustsHeightRuntime() {
        flicker.assertLayersStart {
            val topLayerRegion =
                    this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
            val bottomLayerRegion =
                    this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
            // Compare dimensions of two splits, given we're using default split attributes,
            // both activities take up the same visible size on the display.
            check { "height" }
                    .that(topLayerRegion.region.height).isEqual(bottomLayerRegion.region.height)
            check { "width" }
                    .that(topLayerRegion.region.width).isEqual(bottomLayerRegion.region.width)
            topLayerRegion.notOverlaps(bottomLayerRegion.region)
            // Layers of two activities sum to be fullscreen size on display.
            topLayerRegion.plus(bottomLayerRegion.region).coversExactly(startDisplayBounds)
        }

        flicker.assertLayersEnd {
            val topLayerRegion =
                    this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
            val bottomLayerRegion =
                    this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
            // Compare dimensions of two splits, given we're using default split attributes,
            // both activities take up the same visible size on the display.
            check { "height" }
                    .that(topLayerRegion.region.height).isLower(bottomLayerRegion.region.height)
            check { "height" }
                    .that(
                            topLayerRegion.region.height / 0.3f -
                                    bottomLayerRegion.region.height / 0.7f)
                    .isLower(0.1f)
            check { "width" }
                    .that(topLayerRegion.region.width).isEqual(bottomLayerRegion.region.width)
            topLayerRegion.notOverlaps(bottomLayerRegion.region)
            // Layers of two activities sum to be fullscreen size on display.
            topLayerRegion.plus(bottomLayerRegion.region).coversExactly(startDisplayBounds)
        }
    }

    companion object {
        /** {@inheritDoc} */
        private var startDisplayBounds = Rect.EMPTY
        /**
         * Creates the test configurations.
         *
         * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
         * navigation modes.
         */
        @Parameterized.Parameters(name = "{0}")
        @JvmStatic
        fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
    }
}
 No newline at end of file
+0 −8
Original line number Diff line number Diff line
@@ -142,14 +142,6 @@ class OpenThirdActivityOverSplitTest(flicker: LegacyFlickerTest) :
        }
    }

    /** Assert the background animation layer is never visible during transition. */
    @Presubmit
    @Test
    fun backgroundLayerNeverVisible() {
        val backgroundColorLayer = ComponentNameMatcher("", "Animation Background")
        flicker.assertLayers { isInvisible(backgroundColorLayer) }
    }

    companion object {
        /** {@inheritDoc} */
        private var startDisplayBounds = Rect.EMPTY
Loading