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

Commit 6a3dfb25 authored by Chris Li's avatar Chris Li
Browse files

Skip ActivityEmbedding animation if it is behind an app starting window

Bug: 207070762
Test: atest WMShellUnitTests:ActivityEmbeddingAnimationRunnerTests
Test: atest WmTests:TransitionTests
Change-Id: I602201646040f3358a688dcb6ec779f8244953ac
parent 7c90ab5b
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -125,8 +125,15 @@ 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;

    /**
     * Whether the window is covered by an app starting window. This is different from
     * {@link #FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT} which is only set on the Activity window
     * that contains the starting window.
     */
    public static final int FLAG_IS_BEHIND_STARTING_WINDOW = 1 << 14;

    /** 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;
    public static final int FLAG_FIRST_CUSTOM = 1 << 15;

    /** @hide */
    @IntDef(prefix = { "FLAG_" }, value = {
@@ -145,6 +152,7 @@ public final class TransitionInfo implements Parcelable {
            FLAG_WILL_IME_SHOWN,
            FLAG_CROSS_PROFILE_OWNER_THUMBNAIL,
            FLAG_CROSS_PROFILE_WORK_THUMBNAIL,
            FLAG_IS_BEHIND_STARTING_WINDOW,
            FLAG_FIRST_CUSTOM
    })
    public @interface ChangeFlags {}
@@ -351,6 +359,9 @@ public final class TransitionInfo implements Parcelable {
        if ((flags & FLAG_FILLS_TASK) != 0) {
            sb.append(sb.length() == 0 ? "" : "|").append("FILLS_TASK");
        }
        if ((flags & FLAG_IS_BEHIND_STARTING_WINDOW) != 0) {
            sb.append(sb.length() == 0 ? "" : "|").append("IS_BEHIND_STARTING_WINDOW");
        }
        if ((flags & FLAG_FIRST_CUSTOM) != 0) {
            sb.append(sb.length() == 0 ? "" : "|").append("FIRST_CUSTOM");
        }
+11 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.wm.shell.activityembedding;

import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;

import android.animation.Animator;
import android.animation.ValueAnimator;
@@ -129,12 +130,20 @@ class ActivityEmbeddingAnimationRunner {
    @NonNull
    private List<ActivityEmbeddingAnimationAdapter> createAnimationAdapters(
            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) {
        boolean isChangeTransition = false;
        for (TransitionInfo.Change change : info.getChanges()) {
            if (change.getMode() == TRANSIT_CHANGE
            if (change.hasFlags(FLAG_IS_BEHIND_STARTING_WINDOW)) {
                // Skip the animation if the windows are behind an app starting window.
                return new ArrayList<>();
            }
            if (!isChangeTransition && change.getMode() == TRANSIT_CHANGE
                    && !change.getStartAbsBounds().equals(change.getEndAbsBounds())) {
                return createChangeAnimationAdapters(info, startTransaction);
                isChangeTransition = true;
            }
        }
        if (isChangeTransition) {
            return createChangeAnimationAdapters(info, startTransaction);
        }
        if (Transitions.isClosingType(info.getType())) {
            return createCloseAnimationAdapters(info);
        }
+17 −0
Original line number Diff line number Diff line
@@ -18,7 +18,9 @@ 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 android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
@@ -27,6 +29,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;

import android.animation.Animator;
import android.window.TransitionInfo;

import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -76,4 +79,18 @@ public class ActivityEmbeddingAnimationRunnerTests extends ActivityEmbeddingAnim

        verify(mController).onAnimationFinished(mTransition);
    }

    @Test
    public void testChangesBehindStartingWindow() {
        final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 0);
        final TransitionInfo.Change embeddingChange = createChange();
        embeddingChange.setFlags(FLAG_IS_BEHIND_STARTING_WINDOW);
        info.addChange(embeddingChange);
        final Animator animator = mAnimRunner.createAnimator(
                info, mStartTransaction, mFinishTransaction,
                () -> mFinishCallback.onTransitionFinished(null /* wct */, null /* wctCB */));

        // The animation should be empty when it is behind starting window.
        assertEquals(0, animator.getDuration());
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ 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_BEHIND_STARTING_WINDOW;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.TransitionInfo.FLAG_IS_INPUT_METHOD;
import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION;
@@ -1894,6 +1895,10 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
                    // Whether this is in a Task with embedded activity.
                    flags |= FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
                }
                if (parentTask.forAllActivities(ActivityRecord::hasStartingWindow)) {
                    // The starting window should cover all windows inside the leaf Task.
                    flags |= FLAG_IS_BEHIND_STARTING_WINDOW;
                }
                if (isWindowFillingTask(wc, parentTask)) {
                    // Whether the container fills its parent Task bounds.
                    flags |= FLAG_FILLS_TASK;
+34 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
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;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
@@ -1073,6 +1074,39 @@ public class TransitionTests extends WindowTestsBase {
        assertTrue(openTransition.allReady());
    }

    @Test
    public void testIsBehindStartingWindowChange() {
        final Transition transition = createTestTransition(TRANSIT_OPEN);
        final ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
        final ArraySet<WindowContainer> participants = transition.mParticipants;

        final Task task = createTask(mDisplayContent);
        final ActivityRecord activity0 = createActivityRecord(task);
        final ActivityRecord activity1 = createActivityRecord(task);
        doReturn(true).when(activity1).hasStartingWindow();

        // Start states.
        changes.put(activity0, new Transition.ChangeInfo(true /* vis */, false /* exChg */));
        changes.put(activity1, new Transition.ChangeInfo(false /* vis */, false /* exChg */));
        // End states.
        activity0.mVisibleRequested = false;
        activity1.mVisibleRequested = true;

        participants.add(activity0);
        participants.add(activity1);
        final ArrayList<WindowContainer> targets = Transition.calculateTargets(
                participants, changes);
        final TransitionInfo info = Transition.calculateTransitionInfo(
                transition.mType, 0 /* flags */, targets, changes, mMockT);

        // All windows in the Task should have FLAG_IS_BEHIND_STARTING_WINDOW because the starting
        // window should cover the whole Task.
        assertEquals(2, info.getChanges().size());
        assertTrue(info.getChanges().get(0).hasFlags(FLAG_IS_BEHIND_STARTING_WINDOW));
        assertTrue(info.getChanges().get(1).hasFlags(FLAG_IS_BEHIND_STARTING_WINDOW));

    }

    @Test
    public void testFlagInTaskWithEmbeddedActivity() {
        final Transition transition = createTestTransition(TRANSIT_OPEN);