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

Commit 05492f06 authored by Perry Wu's avatar Perry Wu
Browse files

[PIP2] Fix rounded corners for alpha enter

Fixed issue where the alpha enter animator did not have rounded corners.

Bug: 385152045
Flag: com.android.wm.shell.enable_pip2
Test: http://recall/-/cidfAmGe9UaIuFMHR3GEC8/bKJhY0JbCTOv0pd3Dj88Ub
Test: atest WMShellUnitTests:PipAlphaAnimatorTest
Change-Id: Ifa7a5e0a4f3b925b84de9a2748fc871f64dd4cb3
parent 46d15f86
Loading
Loading
Loading
Loading
+37 −9
Original line number Diff line number Diff line
@@ -50,6 +50,11 @@ public class PipAlphaAnimator extends ValueAnimator {

    private final SurfaceControl mLeash;
    private final SurfaceControl.Transaction mStartTransaction;
    private final SurfaceControl.Transaction mFinishTransaction;

    private final int mDirection;
    private final int mCornerRadius;
    private final int mShadowRadius;

    private final Animator.AnimatorListener mAnimatorListener = new AnimatorListenerAdapter() {
        @Override
@@ -59,6 +64,7 @@ public class PipAlphaAnimator extends ValueAnimator {
                mAnimationStartCallback.run();
            }
            if (mStartTransaction != null) {
                onAlphaAnimationUpdate(getStartAlphaValue(), mStartTransaction);
                mStartTransaction.apply();
            }
        }
@@ -66,6 +72,10 @@ public class PipAlphaAnimator extends ValueAnimator {
        @Override
        public void onAnimationEnd(Animator animation) {
            super.onAnimationEnd(animation);
            if (mFinishTransaction != null) {
                onAlphaAnimationUpdate(getEndAlphaValue(), mFinishTransaction);
                mFinishTransaction.apply();
            }
            if (mAnimationEndCallback != null) {
                mAnimationEndCallback.run();
            }
@@ -77,8 +87,9 @@ public class PipAlphaAnimator extends ValueAnimator {
                @Override
                public void onAnimationUpdate(@NonNull ValueAnimator animation) {
                    final float alpha = (Float) animation.getAnimatedValue();
                    mSurfaceControlTransactionFactory.getTransaction()
                            .setAlpha(mLeash, alpha).apply();
                    final SurfaceControl.Transaction tx =
                            mSurfaceControlTransactionFactory.getTransaction();
                    onAlphaAnimationUpdate(alpha, tx);
                }
            };

@@ -91,19 +102,21 @@ public class PipAlphaAnimator extends ValueAnimator {

    public PipAlphaAnimator(Context context,
            SurfaceControl leash,
            SurfaceControl.Transaction tx,
            SurfaceControl.Transaction startTransaction,
            SurfaceControl.Transaction finishTransaction,
            @Fade int direction) {
        mLeash = leash;
        mStartTransaction = tx;
        if (direction == FADE_IN) {
            setFloatValues(0f, 1f);
        } else { // direction == FADE_OUT
            setFloatValues(1f, 0f);
        }
        mStartTransaction = startTransaction;
        mFinishTransaction = finishTransaction;

        mDirection = direction;
        setFloatValues(getStartAlphaValue(), getEndAlphaValue());
        mSurfaceControlTransactionFactory =
                new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
        final int enterAnimationDuration = context.getResources()
                .getInteger(R.integer.config_pipEnterAnimationDuration);
        mCornerRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
        mShadowRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius);
        setDuration(enterAnimationDuration);
        addListener(mAnimatorListener);
        addUpdateListener(mAnimatorUpdateListener);
@@ -117,6 +130,21 @@ public class PipAlphaAnimator extends ValueAnimator {
        mAnimationEndCallback = runnable;
    }

    private void onAlphaAnimationUpdate(float alpha, SurfaceControl.Transaction tx) {
        tx.setAlpha(mLeash, alpha)
                .setCornerRadius(mLeash, mCornerRadius)
                .setShadowRadius(mLeash, mShadowRadius);
        tx.apply();
    }

    private float getStartAlphaValue() {
        return mDirection == FADE_IN ? 0f : 1f;
    }

    private float getEndAlphaValue() {
        return mDirection == FADE_IN ? 1f : 0f;
    }

    @VisibleForTesting
    void setSurfaceControlTransactionFactory(
            @NonNull PipSurfaceTransactionHelper.SurfaceControlTransactionFactory factory) {
+2 −1
Original line number Diff line number Diff line
@@ -294,7 +294,8 @@ public class PipScheduler {
    interface PipAlphaAnimatorSupplier {
        PipAlphaAnimator get(@NonNull Context context,
                SurfaceControl leash,
                SurfaceControl.Transaction tx,
                SurfaceControl.Transaction startTransaction,
                SurfaceControl.Transaction finishTransaction,
                @PipAlphaAnimator.Fade int direction);
    }

+3 −3
Original line number Diff line number Diff line
@@ -513,7 +513,7 @@ public class PipTransition extends PipTransitionController implements
    private void startOverlayFadeoutAnimation(@NonNull SurfaceControl overlayLeash,
            @NonNull Runnable onAnimationEnd) {
        PipAlphaAnimator animator = new PipAlphaAnimator(mContext, overlayLeash,
                null /* startTx */, PipAlphaAnimator.FADE_OUT);
                null /* startTx */, null /* finishTx */, PipAlphaAnimator.FADE_OUT);
        animator.setDuration(CONTENT_OVERLAY_FADE_OUT_DELAY_MS);
        animator.setAnimationEndCallback(onAnimationEnd);
        animator.start();
@@ -604,7 +604,7 @@ public class PipTransition extends PipTransitionController implements
                .setAlpha(pipLeash, 0f);

        PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipLeash, startTransaction,
                PipAlphaAnimator.FADE_IN);
                finishTransaction, PipAlphaAnimator.FADE_IN);
        // This should update the pip transition state accordingly after we stop playing.
        animator.setAnimationEndCallback(this::finishTransition);
        cacheAndStartTransitionAnimator(animator);
@@ -699,7 +699,7 @@ public class PipTransition extends PipTransitionController implements
        finishTransaction.setAlpha(pipChange.getLeash(), 0f);
        if (mPendingRemoveWithFadeout) {
            PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipChange.getLeash(),
                    startTransaction, PipAlphaAnimator.FADE_OUT);
                    startTransaction, finishTransaction, PipAlphaAnimator.FADE_OUT);
            animator.setAnimationEndCallback(this::finishTransition);
            animator.start();
        } else {
+92 −17
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.wm.shell.pip2.animation;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -33,6 +35,7 @@ import android.view.SurfaceControl;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;

import com.android.wm.shell.R;
import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;

import org.junit.Before;
@@ -48,6 +51,8 @@ import org.mockito.MockitoAnnotations;
@TestableLooper.RunWithLooper
@RunWith(AndroidTestingRunner.class)
public class PipAlphaAnimatorTest {
    private static final float TEST_CORNER_RADIUS = 1f;
    private static final float TEST_SHADOW_RADIUS = 2f;

    @Mock private Context mMockContext;

@@ -55,7 +60,9 @@ public class PipAlphaAnimatorTest {

    @Mock private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mMockFactory;

    @Mock private SurfaceControl.Transaction mMockTransaction;
    @Mock private SurfaceControl.Transaction mMockAnimateTransaction;
    @Mock private SurfaceControl.Transaction mMockStartTransaction;
    @Mock private SurfaceControl.Transaction mMockFinishTransaction;

    @Mock private Runnable mMockStartCallback;

@@ -69,9 +76,15 @@ public class PipAlphaAnimatorTest {
        MockitoAnnotations.initMocks(this);
        when(mMockContext.getResources()).thenReturn(mMockResources);
        when(mMockResources.getInteger(anyInt())).thenReturn(0);
        when(mMockFactory.getTransaction()).thenReturn(mMockTransaction);
        when(mMockTransaction.setAlpha(any(SurfaceControl.class), anyFloat()))
                .thenReturn(mMockTransaction);
        when(mMockFactory.getTransaction()).thenReturn(mMockAnimateTransaction);
        when(mMockResources.getDimensionPixelSize(R.dimen.pip_corner_radius))
                .thenReturn((int) TEST_CORNER_RADIUS);
        when(mMockResources.getDimensionPixelSize(R.dimen.pip_shadow_radius))
                .thenReturn((int) TEST_SHADOW_RADIUS);

        prepareTransaction(mMockAnimateTransaction);
        prepareTransaction(mMockStartTransaction);
        prepareTransaction(mMockFinishTransaction);

        mTestLeash = new SurfaceControl.Builder()
                .setContainerLayer()
@@ -82,8 +95,8 @@ public class PipAlphaAnimatorTest {

    @Test
    public void setAnimationStartCallback_fadeInAnimator_callbackStartCallback() {
        mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockTransaction,
                PipAlphaAnimator.FADE_IN);
        mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction,
                mMockFinishTransaction, PipAlphaAnimator.FADE_IN);

        mPipAlphaAnimator.setAnimationStartCallback(mMockStartCallback);
        mPipAlphaAnimator.setAnimationEndCallback(mMockEndCallback);
@@ -98,8 +111,8 @@ public class PipAlphaAnimatorTest {

    @Test
    public void setAnimationEndCallback_fadeInAnimator_callbackStartAndEndCallback() {
        mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockTransaction,
                PipAlphaAnimator.FADE_IN);
        mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction,
                mMockFinishTransaction, PipAlphaAnimator.FADE_IN);

        mPipAlphaAnimator.setAnimationStartCallback(mMockStartCallback);
        mPipAlphaAnimator.setAnimationEndCallback(mMockEndCallback);
@@ -109,36 +122,98 @@ public class PipAlphaAnimatorTest {
        });

        verify(mMockStartCallback).run();
        verify(mMockStartCallback).run();
        verify(mMockEndCallback).run();
    }

    @Test
    public void onAnimationStart_setCornerAndShadowRadii() {
        mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction,
                mMockFinishTransaction, PipAlphaAnimator.FADE_IN);
        mPipAlphaAnimator.setSurfaceControlTransactionFactory(mMockFactory);

        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
            mPipAlphaAnimator.start();
            mPipAlphaAnimator.pause();
        });

        verify(mMockStartTransaction, atLeastOnce())
                .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
        verify(mMockStartTransaction, atLeastOnce())
                .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
    }

    @Test
    public void onAnimationUpdate_setCornerAndShadowRadii() {
        mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction,
                mMockFinishTransaction, PipAlphaAnimator.FADE_IN);
        mPipAlphaAnimator.setSurfaceControlTransactionFactory(mMockFactory);

        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
            mPipAlphaAnimator.start();
            mPipAlphaAnimator.pause();
        });

        verify(mMockAnimateTransaction, atLeastOnce())
                .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
        verify(mMockAnimateTransaction, atLeastOnce())
                .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
    }

    @Test
    public void onAnimationEnd_setCornerAndShadowRadii() {
        mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction,
                mMockFinishTransaction, PipAlphaAnimator.FADE_IN);
        mPipAlphaAnimator.setSurfaceControlTransactionFactory(mMockFactory);

        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
            mPipAlphaAnimator.start();
            mPipAlphaAnimator.end();
        });

        verify(mMockFinishTransaction, atLeastOnce())
                .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
        verify(mMockFinishTransaction, atLeastOnce())
                .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
    }

    @Test
    public void onAnimationEnd_fadeInAnimator_leashVisibleAtEnd() {
        mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockTransaction,
                PipAlphaAnimator.FADE_IN);
        mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction,
                mMockFinishTransaction, PipAlphaAnimator.FADE_IN);
        mPipAlphaAnimator.setSurfaceControlTransactionFactory(mMockFactory);

        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
            mPipAlphaAnimator.start();
            clearInvocations(mMockTransaction);
            clearInvocations(mMockAnimateTransaction);
            mPipAlphaAnimator.end();
        });

        verify(mMockTransaction).setAlpha(mTestLeash, 1.0f);
        verify(mMockAnimateTransaction).setAlpha(mTestLeash, 1.0f);
    }

    @Test
    public void onAnimationEnd_fadeOutAnimator_leashInvisibleAtEnd() {
        mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockTransaction,
                PipAlphaAnimator.FADE_OUT);
        mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction,
                mMockFinishTransaction, PipAlphaAnimator.FADE_OUT);
        mPipAlphaAnimator.setSurfaceControlTransactionFactory(mMockFactory);

        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
            mPipAlphaAnimator.start();
            clearInvocations(mMockTransaction);
            clearInvocations(mMockAnimateTransaction);
            mPipAlphaAnimator.end();
        });

        verify(mMockTransaction).setAlpha(mTestLeash, 0f);
        verify(mMockAnimateTransaction).setAlpha(mTestLeash, 0f);
    }


    // set up transaction chaining
    private void prepareTransaction(SurfaceControl.Transaction tx) {
        when(tx.setAlpha(any(SurfaceControl.class), anyFloat()))
                .thenReturn(tx);
        when(tx.setCornerRadius(any(SurfaceControl.class), anyFloat()))
                .thenReturn(tx);
        when(tx.setShadowRadius(any(SurfaceControl.class), anyFloat()))
                .thenReturn(tx);
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -111,7 +111,7 @@ public class PipSchedulerTest {
                mRootTaskDisplayAreaOrganizer);
        mPipScheduler.setPipTransitionController(mMockPipTransitionController);
        mPipScheduler.setSurfaceControlTransactionFactory(mMockFactory);
        mPipScheduler.setPipAlphaAnimatorSupplier((context, leash, tx, direction) ->
        mPipScheduler.setPipAlphaAnimatorSupplier((context, leash, startTx, finishTx, direction) ->
                mMockAlphaAnimator);

        SurfaceControl testLeash = new SurfaceControl.Builder()