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

Commit 7eb3933a authored by Chris Li's avatar Chris Li Committed by Android (Google) Code Review
Browse files

Merge "Only play ActivityEmbedding animation if there is AE split" into tm-qpr-dev

parents 941a2e72 b74873a4
Loading
Loading
Loading
Loading
+13 −4
Original line number Diff line number Diff line
@@ -113,8 +113,8 @@ public final class TransitionInfo implements Parcelable {
    /** The container is in a Task with embedded activity. */
    public static final int FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY = 1 << 9;

    /** The first unused bit. This can be used by remotes to attach custom flags to this change. */
    public static final int FLAG_FIRST_CUSTOM = 1 << 10;
    /** The container fills its parent Task before and after the transition. */
    public static final int FLAG_FILLS_TASK = 1 << 10;

    /** The container is going to show IME on its task after the transition. */
    public static final int FLAG_WILL_IME_SHOWN = 1 << 11;
@@ -125,6 +125,9 @@ public final class TransitionInfo implements Parcelable {
    /** The container attaches work profile thumbnail for cross profile animation. */
    public static final int FLAG_CROSS_PROFILE_WORK_THUMBNAIL = 1 << 13;

    /** The first unused bit. This can be used by remotes to attach custom flags to this change. */
    public static final int FLAG_FIRST_CUSTOM = 1 << 14;

    /** @hide */
    @IntDef(prefix = { "FLAG_" }, value = {
            FLAG_NONE,
@@ -138,8 +141,11 @@ public final class TransitionInfo implements Parcelable {
            FLAG_DISPLAY_HAS_ALERT_WINDOWS,
            FLAG_IS_INPUT_METHOD,
            FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY,
            FLAG_FIRST_CUSTOM,
            FLAG_WILL_IME_SHOWN
            FLAG_FILLS_TASK,
            FLAG_WILL_IME_SHOWN,
            FLAG_CROSS_PROFILE_OWNER_THUMBNAIL,
            FLAG_CROSS_PROFILE_WORK_THUMBNAIL,
            FLAG_FIRST_CUSTOM
    })
    public @interface ChangeFlags {}

@@ -342,6 +348,9 @@ public final class TransitionInfo implements Parcelable {
        if ((flags & FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY) != 0) {
            sb.append(sb.length() == 0 ? "" : "|").append("IN_TASK_WITH_EMBEDDED_ACTIVITY");
        }
        if ((flags & FLAG_FILLS_TASK) != 0) {
            sb.append(sb.length() == 0 ? "" : "|").append("FILLS_TASK");
        }
        if ((flags & FLAG_FIRST_CUSTOM) != 0) {
            sb.append(sb.length() == 0 ? "" : "|").append("FIRST_CUSTOM");
        }
+13 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.wm.shell.activityembedding;

import static android.window.TransitionInfo.FLAG_FILLS_TASK;
import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;

import static java.util.Objects.requireNonNull;
@@ -84,12 +85,23 @@ public class ActivityEmbeddingController implements Transitions.TransitionHandle
            @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction,
            @NonNull Transitions.TransitionFinishCallback finishCallback) {
        // TODO(b/207070762) Handle AE animation as a part of other transitions.
        boolean containsEmbeddingSplit = false;
        for (TransitionInfo.Change change : info.getChanges()) {
            if (!change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) {
                // Only animate the transition if all changes are in a Task with ActivityEmbedding.
                return false;
            }
            if (!containsEmbeddingSplit && !change.hasFlags(FLAG_FILLS_TASK)) {
                // Whether the Task contains any ActivityEmbedding split before or after the
                // transition.
                containsEmbeddingSplit = true;
            }
        }
        if (!containsEmbeddingSplit) {
            // Let the system to play the default animation if there is no ActivityEmbedding split
            // window. This allows to play the app customized animation when there is no embedding,
            // such as the device is in a folded state.
            return false;
        }

        // Start ActivityEmbedding animation.
+24 −0
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.wm.shell.activityembedding;

import static android.window.TransitionInfo.FLAG_FILLS_TASK;
import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;

import static org.junit.Assert.assertNotNull;
@@ -24,6 +27,8 @@ import static org.mockito.Mockito.mock;

import android.animation.Animator;
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.graphics.Rect;
import android.os.IBinder;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
@@ -80,4 +85,23 @@ abstract class ActivityEmbeddingAnimationTestBase extends ShellTestCase {
        return new TransitionInfo.Change(mock(WindowContainerToken.class),
                mock(SurfaceControl.class));
    }

    /**
     * Creates a mock {@link TransitionInfo.Change} with
     * {@link TransitionInfo#FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY} flag.
     */
    static TransitionInfo.Change createEmbeddedChange(@NonNull Rect startBounds,
            @NonNull Rect endBounds, @NonNull Rect taskBounds) {
        final TransitionInfo.Change change = createChange();
        change.setFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY);
        change.setStartAbsBounds(startBounds);
        change.setEndAbsBounds(endBounds);
        if (taskBounds.width() == startBounds.width()
                && taskBounds.height() == startBounds.height()
                && taskBounds.width() == endBounds.width()
                && taskBounds.height() == endBounds.height()) {
            change.setFlags(FLAG_FILLS_TASK);
        }
        return change;
    }
}
+66 −10
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.wm.shell.activityembedding;

import static android.view.WindowManager.TRANSIT_OPEN;
import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;

@@ -29,6 +28,7 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;

import android.graphics.Rect;
import android.window.TransitionInfo;

import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -48,6 +48,10 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimationTestBase {

    private static final Rect TASK_BOUNDS = new Rect(0, 0, 1000, 500);
    private static final Rect EMBEDDED_LEFT_BOUNDS = new Rect(0, 0, 500, 500);
    private static final Rect EMBEDDED_RIGHT_BOUNDS = new Rect(500, 0, 1000, 500);

    @Before
    public void setup() {
        super.setUp();
@@ -77,13 +81,13 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation
    @Test
    public void testStartAnimation_containsNonActivityEmbeddingChange() {
        final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 0);
        final TransitionInfo.Change embeddingChange = createChange();
        embeddingChange.setFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY);
        final TransitionInfo.Change embeddingChange = createEmbeddedChange(EMBEDDED_LEFT_BOUNDS,
                EMBEDDED_LEFT_BOUNDS, TASK_BOUNDS);
        final TransitionInfo.Change nonEmbeddingChange = createChange();
        info.addChange(embeddingChange);
        info.addChange(nonEmbeddingChange);

        // No-op
        // No-op because it contains non-embedded change.
        assertFalse(mController.startAnimation(mTransition, info, mStartTransaction,
                mFinishTransaction, mFinishCallback));
        verify(mAnimRunner, never()).startAnimation(any(), any(), any(), any());
@@ -93,13 +97,65 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation
    }

    @Test
    public void testStartAnimation_onlyActivityEmbeddingChange() {
    public void testStartAnimation_containsOnlyFillTaskActivityEmbeddingChange() {
        final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 0);
        final TransitionInfo.Change embeddingChange = createEmbeddedChange(TASK_BOUNDS, TASK_BOUNDS,
                TASK_BOUNDS);
        info.addChange(embeddingChange);

        // No-op because it only contains embedded change that fills the Task. We will let the
        // default handler to animate such transition.
        assertFalse(mController.startAnimation(mTransition, info, mStartTransaction,
                mFinishTransaction, mFinishCallback));
        verify(mAnimRunner, never()).startAnimation(any(), any(), any(), any());
        verifyNoMoreInteractions(mStartTransaction);
        verifyNoMoreInteractions(mFinishTransaction);
        verifyNoMoreInteractions(mFinishCallback);
    }

    @Test
    public void testStartAnimation_containsActivityEmbeddingSplitChange() {
        // Change that occupies only part of the Task.
        final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 0);
        final TransitionInfo.Change embeddingChange = createEmbeddedChange(EMBEDDED_LEFT_BOUNDS,
                EMBEDDED_LEFT_BOUNDS, TASK_BOUNDS);
        info.addChange(embeddingChange);

        // ActivityEmbeddingController will handle such transition.
        assertTrue(mController.startAnimation(mTransition, info, mStartTransaction,
                mFinishTransaction, mFinishCallback));
        verify(mAnimRunner).startAnimation(mTransition, info, mStartTransaction,
                mFinishTransaction);
        verify(mStartTransaction).apply();
        verifyNoMoreInteractions(mFinishTransaction);
    }

    @Test
    public void testStartAnimation_containsChangeEnterActivityEmbeddingSplit() {
        // Change that is entering ActivityEmbedding split.
        final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 0);
        final TransitionInfo.Change embeddingChange = createEmbeddedChange(TASK_BOUNDS,
                EMBEDDED_LEFT_BOUNDS, TASK_BOUNDS);
        info.addChange(embeddingChange);

        // ActivityEmbeddingController will handle such transition.
        assertTrue(mController.startAnimation(mTransition, info, mStartTransaction,
                mFinishTransaction, mFinishCallback));
        verify(mAnimRunner).startAnimation(mTransition, info, mStartTransaction,
                mFinishTransaction);
        verify(mStartTransaction).apply();
        verifyNoMoreInteractions(mFinishTransaction);
    }

    @Test
    public void testStartAnimation_containsChangeExitActivityEmbeddingSplit() {
        // Change that is exiting ActivityEmbedding split.
        final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 0);
        final TransitionInfo.Change embeddingChange = createChange();
        embeddingChange.setFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY);
        final TransitionInfo.Change embeddingChange = createEmbeddedChange(EMBEDDED_RIGHT_BOUNDS,
                TASK_BOUNDS, TASK_BOUNDS);
        info.addChange(embeddingChange);

        // No-op
        // ActivityEmbeddingController will handle such transition.
        assertTrue(mController.startAnimation(mTransition, info, mStartTransaction,
                mFinishTransaction, mFinishCallback));
        verify(mAnimRunner).startAnimation(mTransition, info, mStartTransaction,
@@ -115,8 +171,8 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation
                () -> mController.onAnimationFinished(mTransition));

        final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 0);
        final TransitionInfo.Change embeddingChange = createChange();
        embeddingChange.setFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY);
        final TransitionInfo.Change embeddingChange = createEmbeddedChange(EMBEDDED_LEFT_BOUNDS,
                EMBEDDED_LEFT_BOUNDS, TASK_BOUNDS);
        info.addChange(embeddingChange);
        mController.startAnimation(mTransition, info, mStartTransaction,
                mFinishTransaction, mFinishCallback);
+16 −4
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import static android.view.WindowManager.TransitionFlags;
import static android.view.WindowManager.TransitionType;
import static android.view.WindowManager.transitTypeToString;
import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
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_DISPLAY;
import static android.window.TransitionInfo.FLAG_IS_INPUT_METHOD;
@@ -1888,11 +1889,22 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
            if (taskFragment != null && task == null) {
                parentTask = taskFragment.getTask();
            }
            if (parentTask != null
                    && parentTask.forAllLeafTaskFragments(TaskFragment::isEmbedded)) {
            if (parentTask != null) {
                if (parentTask.forAllLeafTaskFragments(TaskFragment::isEmbedded)) {
                    // Whether this is in a Task with embedded activity.
                    flags |= FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
                }
                final Rect taskBounds = parentTask.getBounds();
                final Rect startBounds = mAbsoluteBounds;
                final Rect endBounds = wc.getBounds();
                if (taskBounds.width() == startBounds.width()
                        && taskBounds.height() == startBounds.height()
                        && taskBounds.width() == endBounds.width()
                        && taskBounds.height() == endBounds.height()) {
                    // Whether the container fills the Task bounds before and after the transition.
                    flags |= FLAG_FILLS_TASK;
                }
            }
            final DisplayContent dc = wc.asDisplayContent();
            if (dc != null) {
                flags |= FLAG_IS_DISPLAY;
Loading