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

Commit af681fdc authored by Charles Chen's avatar Charles Chen
Browse files

Apply AnimationOptions for Embedded Tf

There are legacy usages to override Activity Embedding animation
by Activity#overrideActivityTransition or #overridePendingTransition.

We should also apply the AnimationOptions if there's no override
from TaskFragmentAnimationParams.

Test: atest WmTests:TransitionTests
Bug: 348508863
Flag: EXEMPT bugfix

Change-Id: Iee66aaa860544110f53dd9ee40bc325357c408c1
parent 1d1a9c34
Loading
Loading
Loading
Loading
+20 −3
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.wm;

import static android.app.ActivityOptions.ANIM_CUSTOM;
import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
@@ -1897,7 +1898,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
        }
    }

    private void overrideAnimationOptionsToInfoIfNecessary(@NonNull TransitionInfo info) {
    @VisibleForTesting
    void overrideAnimationOptionsToInfoIfNecessary(@NonNull TransitionInfo info) {
        if (mOverrideOptions == null) {
            return;
        }
@@ -1914,12 +1916,28 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
                    changes.get(i).setAnimationOptions(mOverrideOptions);
                    // TODO(b/295805497): Extract mBackgroundColor from AnimationOptions.
                    changes.get(i).setBackgroundColor(mOverrideOptions.getBackgroundColor());
                } else if (shouldApplyAnimOptionsToEmbeddedTf(container.asTaskFragment())) {
                    // We only override AnimationOptions because backgroundColor should be from
                    // TaskFragmentAnimationParams.
                    changes.get(i).setAnimationOptions(mOverrideOptions);
                }
            }
        }
        updateActivityTargetForCrossProfileAnimation(info);
    }

    private boolean shouldApplyAnimOptionsToEmbeddedTf(@Nullable TaskFragment taskFragment) {
        if (taskFragment == null || !taskFragment.isEmbedded()) {
            return false;
        }
        if (taskFragment.getAnimationParams().hasOverrideAnimation()) {
            // Always respect animation overrides from TaskFragmentAnimationParams.
            return false;
        }
        // ActivityEmbedding animation adapter only support custom animation
        return mOverrideOptions != null && mOverrideOptions.getType() == ANIM_CUSTOM;
    }

    /**
     * Updates activity open target if {@link #mOverrideOptions} is
     * {@link ANIM_OPEN_CROSS_PROFILE_APPS}.
@@ -1929,8 +1947,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
            return;
        }
        for (int i = 0; i < mTargets.size(); ++i) {
            final ActivityRecord activity = mTargets.get(i).mContainer
                    .asActivityRecord();
            final ActivityRecord activity = mTargets.get(i).mContainer.asActivityRecord();
            final TransitionInfo.Change change = info.getChanges().get(i);
            if (activity == null || change.getMode() != TRANSIT_OPEN) {
                continue;
+221 −5
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.window.TransitionInfo.FLAG_CONFIG_AT_END;
import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_OWNER_THUMBNAIL;
import static android.window.TransitionInfo.FLAG_FILLS_TASK;
import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
@@ -77,13 +78,14 @@ import static java.lang.Integer.MAX_VALUE;

import android.app.ActivityManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.view.SurfaceControl;
@@ -95,6 +97,7 @@ import android.window.ITaskOrganizer;
import android.window.ITransitionPlayer;
import android.window.RemoteTransition;
import android.window.SystemPerformanceHinter;
import android.window.TaskFragmentAnimationParams;
import android.window.TaskFragmentOrganizer;
import android.window.TransitionInfo;

@@ -104,7 +107,6 @@ import androidx.test.filters.SmallTest;
import com.android.internal.graphics.ColorUtils;
import com.android.window.flags.Flags;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -120,16 +122,15 @@ import java.util.function.Function;
 * Build/Install/Run:
 *  atest WmTests:TransitionTests
 */
@EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE)
@SmallTest
@Presubmit
@RunWith(WindowTestRunner.class)
public class TransitionTests extends WindowTestsBase {
    final SurfaceControl.Transaction mMockT = mock(SurfaceControl.Transaction.class);
    private BLASTSyncEngine mSyncEngine;
    private Transition mTransition;
    private TransitionInfo mInfo;

    @Rule
    public SetFlagsRule mRule = new SetFlagsRule();
    private Transition createTestTransition(int transitType, TransitionController controller) {
        final Transition transition = new Transition(transitType, 0 /* flags */, controller,
                controller.mSyncEngine);
@@ -1994,6 +1995,221 @@ public class TransitionTests extends WindowTestsBase {
        assertEquals(expectedBackgroundColor, info.getChanges().get(1).getBackgroundColor());
    }

    @DisableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE)
    @Test
    public void testOverrideAnimationOptionsToInfoIfNecessary_disableAnimOptionsPerChange() {
        initializeOverrideAnimationOptionsTest();
        TransitionInfo.AnimationOptions options = TransitionInfo.AnimationOptions
                .makeCommonAnimOptions("testPackage");
        mTransition.setOverrideAnimation(options, null /* startCallback */,
                null /* finishCallback */);

        mTransition.overrideAnimationOptionsToInfoIfNecessary(mInfo);

        assertEquals(options, mInfo.getAnimationOptions());
    }

    @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE)
    @Test
    public void testOverrideAnimationOptionsToInfoIfNecessary_nonCustomAnimOptions() {
        initializeOverrideAnimationOptionsTest();
        TransitionInfo.AnimationOptions options = TransitionInfo.AnimationOptions
                .makeCommonAnimOptions("testPackage");
        mTransition.setOverrideAnimation(options, null /* startCallback */,
                null /* finishCallback */);

        mTransition.overrideAnimationOptionsToInfoIfNecessary(mInfo);

        final TransitionInfo.Change displayChange = mInfo.getChanges().get(0);
        final TransitionInfo.Change taskChange = mInfo.getChanges().get(1);
        final TransitionInfo.Change embeddedTfChange = mInfo.getChanges().get(2);
        final TransitionInfo.Change activityChange = mInfo.getChanges().get(3);

        assertNull("Display change's AnimationOptions must not be overridden.",
                displayChange.getAnimationOptions());
        assertNull("Task change's AnimationOptions must not be overridden.",
                taskChange.getAnimationOptions());
        assertNull("Embedded TF change's AnimationOptions must not be overridden.",
                embeddedTfChange.getAnimationOptions());
        assertEquals("Activity change's AnimationOptions must be overridden.",
                options, activityChange.getAnimationOptions());
    }

    @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE)
    @Test
    public void testOverrideAnimationOptionsToInfoIfNecessary_crossProfileAnimOptions() {
        initializeOverrideAnimationOptionsTest();
        TransitionInfo.AnimationOptions options = TransitionInfo.AnimationOptions
                .makeCrossProfileAnimOptions();
        mTransition.setOverrideAnimation(options, null /* startCallback */,
                null /* finishCallback */);

        final TransitionInfo.Change displayChange = mInfo.getChanges().get(0);
        final TransitionInfo.Change taskChange = mInfo.getChanges().get(1);
        final TransitionInfo.Change embeddedTfChange = mInfo.getChanges().get(2);
        final TransitionInfo.Change activityChange = mInfo.getChanges().get(3);
        activityChange.setMode(TRANSIT_OPEN);

        mTransition.overrideAnimationOptionsToInfoIfNecessary(mInfo);

        assertNull("Display change's AnimationOptions must not be overridden.",
                displayChange.getAnimationOptions());
        assertNull("Task change's AnimationOptions must not be overridden.",
                taskChange.getAnimationOptions());
        assertNull("Embedded TF change's AnimationOptions must not be overridden.",
                embeddedTfChange.getAnimationOptions());
        assertEquals("Activity change's AnimationOptions must be overridden.",
                options, activityChange.getAnimationOptions());
        assertTrue(activityChange.hasFlags(FLAG_CROSS_PROFILE_OWNER_THUMBNAIL));
    }

    @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE)
    @Test
    public void testOverrideAnimationOptionsToInfoIfNecessary_customAnimOptions() {
        initializeOverrideAnimationOptionsTest();
        TransitionInfo.AnimationOptions options = TransitionInfo.AnimationOptions
                .makeCustomAnimOptions("testPackage", Resources.ID_NULL,
                        TransitionInfo.AnimationOptions.DEFAULT_ANIMATION_RESOURCES_ID,
                        TransitionInfo.AnimationOptions.DEFAULT_ANIMATION_RESOURCES_ID,
                        Color.GREEN, false /* overrideTaskTransition */);
        mTransition.setOverrideAnimation(options, null /* startCallback */,
                null /* finishCallback */);

        mTransition.overrideAnimationOptionsToInfoIfNecessary(mInfo);

        final TransitionInfo.Change displayChange = mInfo.getChanges().get(0);
        final TransitionInfo.Change taskChange = mInfo.getChanges().get(1);
        final TransitionInfo.Change embeddedTfChange = mInfo.getChanges().get(2);
        final TransitionInfo.Change activityChange = mInfo.getChanges().get(3);

        assertNull("Display change's AnimationOptions must not be overridden.",
                displayChange.getAnimationOptions());
        assertNull("Task change's AnimationOptions must not be overridden.",
                taskChange.getAnimationOptions());
        assertEquals("Embedded TF change's AnimationOptions must be overridden.",
                options, embeddedTfChange.getAnimationOptions());
        assertEquals("Embedded TF change's background color must not be overridden.",
                0, embeddedTfChange.getBackgroundColor());
        assertEquals("Activity change's AnimationOptions must be overridden.",
                options, activityChange.getAnimationOptions());
        assertEquals("Activity change's background color must be overridden.",
                options.getBackgroundColor(), activityChange.getBackgroundColor());
    }

    @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE)
    @Test
    public void testOverrideAnimationOptionsToInfoIfNecessary_haveTaskFragmentAnimParams() {
        initializeOverrideAnimationOptionsTest();

        final TaskFragment embeddedTf = mTransition.mTargets.get(2).mContainer.asTaskFragment();
        embeddedTf.setAnimationParams(new TaskFragmentAnimationParams.Builder()
                .setAnimationBackgroundColor(Color.RED)
                .setOpenAnimationResId(0x12345678)
                .build());

        TransitionInfo.AnimationOptions options = TransitionInfo.AnimationOptions
                .makeCustomAnimOptions("testPackage", Resources.ID_NULL,
                        TransitionInfo.AnimationOptions.DEFAULT_ANIMATION_RESOURCES_ID,
                        TransitionInfo.AnimationOptions.DEFAULT_ANIMATION_RESOURCES_ID,
                        Color.GREEN, false /* overrideTaskTransition */);
        mTransition.setOverrideAnimation(options, null /* startCallback */,
                null /* finishCallback */);

        final TransitionInfo.Change displayChange = mInfo.getChanges().get(0);
        final TransitionInfo.Change taskChange = mInfo.getChanges().get(1);
        final TransitionInfo.Change embeddedTfChange = mInfo.getChanges().get(2);
        final TransitionInfo.Change activityChange = mInfo.getChanges().get(3);

        final int expectedColor = embeddedTf.getAnimationParams().getAnimationBackgroundColor();
        embeddedTfChange.setBackgroundColor(expectedColor);
        final TransitionInfo.AnimationOptions expectedOptions = TransitionInfo.AnimationOptions
                .makeCustomAnimOptions("testPackage", 0x12345678,
                        TransitionInfo.AnimationOptions.DEFAULT_ANIMATION_RESOURCES_ID,
                        TransitionInfo.AnimationOptions.DEFAULT_ANIMATION_RESOURCES_ID,
                        0, false /* overrideTaskTransition */);
        embeddedTfChange.setAnimationOptions(expectedOptions);

        mTransition.overrideAnimationOptionsToInfoIfNecessary(mInfo);

        assertNull("Display change's AnimationOptions must not be overridden.",
                displayChange.getAnimationOptions());
        assertNull("Task change's AnimationOptions must not be overridden.",
                taskChange.getAnimationOptions());
        assertEquals("Embedded TF change's AnimationOptions must be overridden.",
                expectedOptions, embeddedTfChange.getAnimationOptions());
        assertEquals("Embedded TF change's background color must not be overridden.",
                expectedColor, embeddedTfChange.getBackgroundColor());
        assertEquals("Activity change's AnimationOptions must be overridden.",
                options, activityChange.getAnimationOptions());
        assertEquals("Activity change's background color must be overridden.",
                options.getBackgroundColor(), activityChange.getBackgroundColor());
    }

    @EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE)
    @Test
    public void testOverrideAnimationOptionsToInfoIfNecessary_customAnimOptionsWithTaskOverride() {
        initializeOverrideAnimationOptionsTest();
        TransitionInfo.AnimationOptions options = TransitionInfo.AnimationOptions
                .makeCustomAnimOptions("testPackage", Resources.ID_NULL,
                        TransitionInfo.AnimationOptions.DEFAULT_ANIMATION_RESOURCES_ID,
                        TransitionInfo.AnimationOptions.DEFAULT_ANIMATION_RESOURCES_ID,
                        Color.GREEN, true /* overrideTaskTransition */);
        mTransition.setOverrideAnimation(options, null /* startCallback */,
                null /* finishCallback */);

        mTransition.overrideAnimationOptionsToInfoIfNecessary(mInfo);

        final TransitionInfo.Change displayChange = mInfo.getChanges().get(0);
        final TransitionInfo.Change taskChange = mInfo.getChanges().get(1);
        final TransitionInfo.Change embeddedTfChange = mInfo.getChanges().get(2);
        final TransitionInfo.Change activityChange = mInfo.getChanges().get(3);

        assertNull("Display change's AnimationOptions must not be overridden.",
                displayChange.getAnimationOptions());
        assertEquals("Task change's AnimationOptions must be overridden.",
                options, taskChange.getAnimationOptions());
        assertEquals("Task change's background color must be overridden.",
                options.getBackgroundColor(), taskChange.getBackgroundColor());
        assertEquals("Embedded TF change's AnimationOptions must be overridden.",
                options, embeddedTfChange.getAnimationOptions());
        assertEquals("Embedded TF change's background color must be overridden.",
                0, embeddedTfChange.getBackgroundColor());
        assertEquals("Activity change's AnimationOptions must be overridden.",
                options, activityChange.getAnimationOptions());
        assertEquals("Activity change's background color must be overridden.",
                options.getBackgroundColor(), activityChange.getBackgroundColor());
    }

    private void initializeOverrideAnimationOptionsTest() {
        mTransition = createTestTransition(TRANSIT_OPEN);

        // Test set AnimationOptions for Activity and Task.
        final Task task = createTask(mDisplayContent);
        // Create an embedded TaskFragment.
        final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
        registerTaskFragmentOrganizer(
                ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()));
        final TaskFragment embeddedTf = createTaskFragmentWithEmbeddedActivity(task, organizer);
        final ActivityRecord nonEmbeddedActivity = createActivityRecord(task);
        mWm.mCurrentUserId = nonEmbeddedActivity.mUserId;

        mTransition.mTargets = new ArrayList<>();
        mTransition.mTargets.add(new Transition.ChangeInfo(mDisplayContent));
        mTransition.mTargets.add(new Transition.ChangeInfo(task));
        mTransition.mTargets.add(new Transition.ChangeInfo(embeddedTf));
        mTransition.mTargets.add(new Transition.ChangeInfo(nonEmbeddedActivity));

        mInfo = new TransitionInfo(TRANSIT_OPEN, 0 /* flags */);
        mInfo.addChange(new TransitionInfo.Change(mDisplayContent.mRemoteToken
                .toWindowContainerToken(), mDisplayContent.getAnimationLeash()));
        mInfo.addChange(new TransitionInfo.Change(task.mRemoteToken.toWindowContainerToken(),
                task.getAnimationLeash()));
        mInfo.addChange(new TransitionInfo.Change(embeddedTf.mRemoteToken.toWindowContainerToken(),
                embeddedTf.getAnimationLeash()));
        mInfo.addChange(new TransitionInfo.Change(null /* container */,
                nonEmbeddedActivity.getAnimationLeash()));
    }

    @Test
    public void testTransitionVisibleChange() {
        registerTestTransitionPlayer();