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

Commit 73c4a2d1 authored by Annie Lin's avatar Annie Lin
Browse files

Allow custom animations for AE change transitions behind a flag.

This change also checks for change transition animations for zero duration, which will now fallback to jump cut. Open/close transition animations already fallback to jump cut when there is an animation specified with no duration.

Bug: 293658614
Demo: https://screencast.googleplex.com/cast/NDU3Nzk5MjQzMTg5NDUyOHxjNjZlODgxMy0xMg
Test: atest ActivityEmbeddingAnimationRunnerTests
Test: Manual - Tested by hardcoding
TaskFragmentAnimationParams.setChangeAnimationResId with a custom
animation. This can later be passed in via Extensions API.
Flag: com.android.window.flags.activity_embedding_animation_customization_flag

Change-Id: Ide3ef1d8bb1800953dc0661219bf31152945f9e0
parent 0ea38e6b
Loading
Loading
Loading
Loading
+27 −6
Original line number Diff line number Diff line
@@ -265,7 +265,7 @@ class ActivityEmbeddingAnimationRunner {
        for (TransitionInfo.Change change : openingChanges) {
            final Animation animation =
                    animationProvider.get(info, change, openingWholeScreenBounds);
            if (animation.getDuration() == 0) {
            if (shouldUseJumpCutForAnimation(animation)) {
                continue;
            }
            final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
@@ -290,7 +290,7 @@ class ActivityEmbeddingAnimationRunner {
            }
            final Animation animation =
                    animationProvider.get(info, change, closingWholeScreenBounds);
            if (animation.getDuration() == 0) {
            if (shouldUseJumpCutForAnimation(animation)) {
                continue;
            }
            final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
@@ -444,8 +444,16 @@ class ActivityEmbeddingAnimationRunner {
            calculateParentBounds(change, boundsAnimationChange, parentBounds);
            // There are two animations in the array. The first one is for the start leash
            // (snapshot), and the second one is for the end leash (TaskFragment).
            final Animation[] animations = mAnimationSpec.createChangeBoundsChangeAnimations(change,
                    parentBounds);
            final Animation[] animations =
                    mAnimationSpec.createChangeBoundsChangeAnimations(info, change, parentBounds);
            // Jump cut if either animation has zero for duration.
            if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
                for (Animation animation : animations) {
                    if (shouldUseJumpCutForAnimation(animation)) {
                        return new ArrayList<>();
                    }
                }
            }
            // Keep track as we might need to add background color for the animation.
            // Although there may be multiple change animation, record one of them is sufficient
            // because the background color will be added to the root leash for the whole animation.
@@ -492,12 +500,19 @@ class ActivityEmbeddingAnimationRunner {
                // window without bounds change.
                animation = ActivityEmbeddingAnimationSpec.createNoopAnimation(change);
            } else if (TransitionUtil.isClosingType(change.getMode())) {
                animation = mAnimationSpec.createChangeBoundsCloseAnimation(change, parentBounds);
                animation =
                        mAnimationSpec.createChangeBoundsCloseAnimation(info, change, parentBounds);
                shouldShowBackgroundColor = false;
            } else {
                animation = mAnimationSpec.createChangeBoundsOpenAnimation(change, parentBounds);
                animation =
                        mAnimationSpec.createChangeBoundsOpenAnimation(info, change, parentBounds);
                shouldShowBackgroundColor = false;
            }
            if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
                if (shouldUseJumpCutForAnimation(animation)) {
                    return new ArrayList<>();
                }
            }
            adapters.add(new ActivityEmbeddingAnimationAdapter(animation, change,
                    TransitionUtil.getRootFor(change, info)));
        }
@@ -640,6 +655,12 @@ class ActivityEmbeddingAnimationRunner {
        return true;
    }

    /** Whether or not to use jump cut based on the animation. */
    @VisibleForTesting
    static boolean shouldUseJumpCutForAnimation(@NonNull Animation animation) {
        return animation.getDuration() == 0;
    }

    /** Updates the changes to end states in {@code startTransaction} for jump cut animation. */
    private void prepareForJumpCut(@NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction startTransaction) {
+27 −7
Original line number Diff line number Diff line
@@ -46,7 +46,6 @@ import com.android.window.flags.Flags;
import com.android.wm.shell.shared.TransitionUtil;

/** Animation spec for ActivityEmbedding transition. */
// TODO(b/206557124): provide an easier way to customize animation
class ActivityEmbeddingAnimationSpec {

    private static final String TAG = "ActivityEmbeddingAnimSpec";
@@ -95,8 +94,14 @@ class ActivityEmbeddingAnimationSpec {

    /** Animation for window that is opening in a change transition. */
    @NonNull
    Animation createChangeBoundsOpenAnimation(@NonNull TransitionInfo.Change change,
            @NonNull Rect parentBounds) {
    Animation createChangeBoundsOpenAnimation(@NonNull TransitionInfo info,
            @NonNull TransitionInfo.Change change, @NonNull Rect parentBounds) {
        if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
            final Animation customAnimation = loadCustomAnimation(info, change);
            if (customAnimation != null) {
                return customAnimation;
            }
        }
        // Use end bounds for opening.
        final Rect bounds = change.getEndAbsBounds();
        final int startLeft;
@@ -123,8 +128,14 @@ class ActivityEmbeddingAnimationSpec {

    /** Animation for window that is closing in a change transition. */
    @NonNull
    Animation createChangeBoundsCloseAnimation(@NonNull TransitionInfo.Change change,
            @NonNull Rect parentBounds) {
    Animation createChangeBoundsCloseAnimation(@NonNull TransitionInfo info,
            @NonNull TransitionInfo.Change change, @NonNull Rect parentBounds) {
        if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
            final Animation customAnimation = loadCustomAnimation(info, change);
            if (customAnimation != null) {
                return customAnimation;
            }
        }
        // Use start bounds for closing.
        final Rect bounds = change.getStartAbsBounds();
        final int endTop;
@@ -155,8 +166,17 @@ class ActivityEmbeddingAnimationSpec {
     *         the second one is for the end leash.
     */
    @NonNull
    Animation[] createChangeBoundsChangeAnimations(@NonNull TransitionInfo.Change change,
            @NonNull Rect parentBounds) {
    Animation[] createChangeBoundsChangeAnimations(@NonNull TransitionInfo info,
            @NonNull TransitionInfo.Change change, @NonNull Rect parentBounds) {
        if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
            // TODO(b/293658614): Support more complicated animations that may need more than a noop
            // animation as the start leash.
            final Animation noopAnimation = createNoopAnimation(change);
            final Animation customAnimation = loadCustomAnimation(info, change);
            if (customAnimation != null) {
                return new Animation[]{noopAnimation, customAnimation};
            }
        }
        // Both start bounds and end bounds are in screen coordinates. We will post translate
        // to the local coordinates in ActivityEmbeddingAnimationAdapter#onAnimationUpdate
        final Rect startBounds = change.getStartAbsBounds();
+16 −0
Original line number Diff line number Diff line
@@ -21,10 +21,12 @@ import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;

import static com.android.wm.shell.activityembedding.ActivityEmbeddingAnimationRunner.calculateParentBounds;
import static com.android.wm.shell.activityembedding.ActivityEmbeddingAnimationRunner.shouldUseJumpCutForAnimation;
import static com.android.wm.shell.transition.Transitions.TRANSIT_TASK_FRAGMENT_DRAG_RESIZE;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
@@ -40,6 +42,8 @@ import android.graphics.Rect;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.window.TransitionInfo;

import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -281,6 +285,18 @@ public class ActivityEmbeddingAnimationRunnerTests extends ActivityEmbeddingAnim
                actualParentBounds);
    }

    @Test
    public void testShouldUseJumpCutForAnimation() {
        final Animation noopAnimation = new AlphaAnimation(0f, 1f);
        assertTrue("Animation without duration should use jump cut.",
                shouldUseJumpCutForAnimation(noopAnimation));

        final Animation alphaAnimation = new AlphaAnimation(0f, 1f);
        alphaAnimation.setDuration(100);
        assertFalse("Animation with duration should not use jump cut.",
                shouldUseJumpCutForAnimation(alphaAnimation));
    }

    @NonNull
    private static TransitionInfo.Change prepareChangeForParentBoundsCalculationTest(
            @NonNull Point endRelOffset, @NonNull Rect endAbsBounds, @NonNull Point endParentSize) {