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

Commit 1491f937 authored by Marzia Favaro's avatar Marzia Favaro Committed by Android (Google) Code Review
Browse files

Merge "TransitionDispatchState for TaskViewTransitions" into main

parents bb277d87 d8fa3054
Loading
Loading
Loading
Loading
+31 −3
Original line number Diff line number Diff line
@@ -26,8 +26,12 @@ import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;

import static com.android.window.flags.Flags.FLAG_EXCLUDE_TASK_FROM_RECENTS;
import static com.android.window.flags.Flags.enableHandlersDebuggingMode;
import static com.android.wm.shell.Flags.FLAG_ENABLE_CREATE_ANY_BUBBLE;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES_NOISY;
import static com.android.wm.shell.transition.TransitionDispatchState.CAPTURED_CHANGE_IN_WRONG_TRANSITION;
import static com.android.wm.shell.transition.TransitionDispatchState.CAPTURED_UNRELATED_CHANGE;
import static com.android.wm.shell.transition.TransitionDispatchState.LOST_RELEVANT_CHANGE;
import static com.android.wm.shell.transition.Transitions.transitTypeToString;

import android.annotation.NonNull;
@@ -59,6 +63,7 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.shared.TransitionUtil;
import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
import com.android.wm.shell.transition.TransitionDispatchState;
import com.android.wm.shell.transition.Transitions;

import java.util.ArrayList;
@@ -716,11 +721,26 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV
                                  @NonNull SurfaceControl.Transaction startTransaction,
                                  @NonNull SurfaceControl.Transaction finishTransaction,
                                  @NonNull Transitions.TransitionFinishCallback finishCallback) {
        if (!Flags.taskViewTransitionsRefactor()) {
            return startAnimationLegacy(transition, info, startTransaction, finishTransaction,
                    finishCallback);
        return startAnimation(transition, info, TransitionDispatchState.getDummyInstance(),
                startTransaction, finishTransaction, finishCallback);
    }

    @Override
    public boolean startAnimation(@NonNull IBinder transition,
                                  @Nullable TransitionInfo transitionInfo,
                                  @NonNull TransitionDispatchState dispatchState,
                                  @NonNull SurfaceControl.Transaction startTransaction,
                                  @NonNull SurfaceControl.Transaction finishTransaction,
                                  @NonNull Transitions.TransitionFinishCallback finishCallback) {
        if (!Flags.taskViewTransitionsRefactor() && !enableHandlersDebuggingMode()) {
            return startAnimationLegacy(transition, transitionInfo, startTransaction,
                    finishTransaction, finishCallback);
        }
        final boolean inDataCollectionModeOnly =
                enableHandlersDebuggingMode() && transitionInfo == null;
        final boolean inAnimationMode = !inDataCollectionModeOnly;
        final TransitionInfo info = inDataCollectionModeOnly ? dispatchState.mInfo : transitionInfo;

        final PendingTransition pending = findPending(transition);
        ProtoLog.d(WM_SHELL_BUBBLES_NOISY, "Transitions.startAnimation(): taskView=%d "
                    + "type=%s transition=%s", pending != null ? pending.mTaskView.hashCode() : -1,
@@ -744,10 +764,16 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV
            final TransitionInfo.Change chg = info.getChanges().get(i);
            if (isValidTaskView(chg, pending)) {
                taskViews.add(chg);
                if (inDataCollectionModeOnly) {
                    dispatchState.addError(this, chg, LOST_RELEVANT_CHANGE);
                }
            } else {
                alienChanges.add(chg);
            }
        }
        if (inDataCollectionModeOnly) {
            return false;
        }

        // Prepare taskViews for animation
        for (int i = 0; i < taskViews.size(); ++i) {
@@ -822,10 +848,12 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV
                Slog.e(TAG, "Found a launching TaskView in the wrong transition. All "
                        + "TaskView launches should be initiated by shell and in their "
                        + "own transition: " + taskInfo.taskId);
                dispatchState.addError(this, change, CAPTURED_CHANGE_IN_WRONG_TRANSITION);
            } else {
                Slog.w(TAG, "Found a non-TaskView task in a TaskView Transition. This "
                        + "shouldn't happen, so there may be a visual artifact: "
                        + taskInfo.taskId);
                dispatchState.addError(this, change, CAPTURED_UNRELATED_CHANGE);
            }
        }

+3 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ public class TransitionDispatchState {
    // Change-related errors
    public static final int LOST_RELEVANT_CHANGE = 3;
    public static final int CAPTURED_UNRELATED_CHANGE = 4;
    public static final int CAPTURED_CHANGE_IN_WRONG_TRANSITION = 5;

    @IntDef(
            value = {
@@ -44,6 +45,7 @@ public class TransitionDispatchState {
                CAPTURED_UNRELATED_FLAG,
                LOST_RELEVANT_CHANGE,
                CAPTURED_UNRELATED_CHANGE,
                CAPTURED_CHANGE_IN_WRONG_TRANSITION,
            })
    public @interface ErrorCode {}

@@ -54,6 +56,7 @@ public class TransitionDispatchState {
            case CAPTURED_UNRELATED_FLAG -> "CAPTURED_UNRELATED_FLAG";
            case LOST_RELEVANT_CHANGE -> "LOST_RELEVANT_CHANGE";
            case CAPTURED_UNRELATED_CHANGE -> "CAPTURED_UNRELATED_CHANGE";
            case CAPTURED_CHANGE_IN_WRONG_TRANSITION -> "CAPTURED_CHANGE_IN_WRONG_TRANSITION";
            default -> "UNKNOWN";
        };
    }
+93 −4
Original line number Diff line number Diff line
@@ -22,7 +22,11 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;

import static com.android.window.flags.Flags.enableHandlersDebuggingMode;
import static com.android.wm.shell.Flags.FLAG_TASK_VIEW_TRANSITIONS_REFACTOR;
import static com.android.wm.shell.Flags.taskViewTransitionsRefactor;
import static com.android.wm.shell.transition.TransitionDispatchState.CAPTURED_UNRELATED_CHANGE;
import static com.android.wm.shell.transition.TransitionDispatchState.LOST_RELEVANT_CHANGE;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -44,6 +48,7 @@ import android.os.IBinder;
import android.platform.test.annotations.UsesFlags;
import android.platform.test.flag.junit.FlagsParameterization;
import android.testing.TestableLooper;
import android.util.Slog;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
import android.window.WindowContainerToken;
@@ -55,6 +60,7 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
import com.android.wm.shell.transition.TransitionDispatchState;
import com.android.wm.shell.transition.TransitionInfoBuilder;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.util.StubTransaction;
@@ -73,9 +79,10 @@ import java.util.List;

/**
 * Class to verify the behavior of startAnimation.
 * Verifies that changes behind FLAG_ENABLE_HANDLERS_DEBUGGING_MODE don't change the behavior
 * of startAnimation. The refactor tests' life span matches the flag's. Permanent tests are meant
 * to be added to TaskViewTransitionsTest.
 * 1. Verifies that startAnimation populates TransitionDispatchState correctly.
 * 2. Verifies that changes behind FLAG_ENABLE_HANDLERS_DEBUGGING_MODE don't change the behavior
 *    of startAnimation. Refactor test's life span matches the flag's. Permanent tests are meant to
 *    be added to TaskViewTransitionsTest.
 *    Test failures that manifest only when the flag is on mean that the behavior diverged.
 */
@SmallTest
@@ -123,6 +130,8 @@ public class TaskViewTransitionStartAnimationTest extends ShellTestCase {
    TaskViewTransitions.PendingTransition mPendingFront;
    TaskViewTransitions.PendingTransition mPendingBack;

    static final String TAG = "TVstartAnimTest";

    public TaskViewTransitionStartAnimationTest(FlagsParameterization flags) {
        mSetFlagsRule.setFlagsParameterization(flags);
    }
@@ -147,6 +156,7 @@ public class TaskViewTransitionStartAnimationTest extends ShellTestCase {
        mUnregisteredTaskInfo.token = mUnregisteredToken;
        // Same id as the other to match pending info id
        mUnregisteredTaskInfo.taskId = 314;
        mUnregisteredTaskInfo.launchCookies.add(mock(IBinder.class));
        mTaskInfo.taskDescription = mock(ActivityManager.TaskDescription.class);

        mBounds = new Rect(0, 0, 100, 100);
@@ -208,6 +218,85 @@ public class TaskViewTransitionStartAnimationTest extends ShellTestCase {
        return pending;
    }

    /**
     * Tests on TransitionDispatchState
     */
    @Test
    public void taskView_dispatchStateFindsIncompatible_animationMode() {
        assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
        assumeTrue(enableHandlersDebuggingMode());
        assumeTrue(taskViewTransitionsRefactor()); // To avoid running twice

        TransitionInfo.Change showingTV = getTaskView(TRANSIT_TO_FRONT);
        TransitionInfo.Change nonTV = getTask(TRANSIT_TO_BACK, false /* registered */);
        TaskViewTransitions.PendingTransition pending =
                setPendingTransaction(true /* visible*/, false /* opening */);
        // Showing taskView + normal task.
        // TaskView is accepted, but normal task is detected as error
        final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TO_FRONT)
                .addChange(showingTV)
                .addChange(nonTV)
                .build();

        TransitionDispatchState dispatchState =
                spy(new TransitionDispatchState(pending.mClaimed, info));

        boolean handled = mTaskViewTransitions.startAnimation(pending.mClaimed, info,
                dispatchState, mStartTransaction, mFinishTransaction, mFinishCallback);

        Slog.v(TAG, "DispatchState:\n" + dispatchState.getDebugInfo());
        // Has animated the taskView
        assertWithMessage("Handler should play the transition")
                .that(handled).isTrue();
        ArgumentCaptor<WindowContainerTransaction> wctCaptor =
                ArgumentCaptor.forClass(WindowContainerTransaction.class);
        verify(mFinishCallback).onTransitionFinished(wctCaptor.capture());
        assertWithMessage("Expected wct to be created and sent to callback")
                .that(wctCaptor.getValue()).isNotNull();
        verify(pending.mTaskView).notifyAppeared(eq(false));

        // Non task-view spotted as intruder
        verify(dispatchState).addError(eq(mTaskViewTransitions), eq(nonTV),
                eq(CAPTURED_UNRELATED_CHANGE));
        assertThat(dispatchState.hasErrors(mTaskViewTransitions)).isTrue();
    }

    @Test
    public void taskView_dispatchStateFindsCompatible_dataCollectionMode() {
        assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
        assumeTrue(enableHandlersDebuggingMode());
        assumeTrue(taskViewTransitionsRefactor()); // To avoid running twice

        TransitionInfo.Change showingTV = getTaskView(TRANSIT_TO_FRONT);
        TransitionInfo.Change nonTV = getTask(TRANSIT_TO_BACK, false /* registered */);
        TaskViewTransitions.PendingTransition pending =
                setPendingTransaction(true /* visible*/, false /* opening */);
        // Showing taskView + normal task.
        // TaskView is detected as change that could have played
        final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TO_FRONT)
                .addChange(showingTV)
                .addChange(nonTV)
                .build();

        TransitionDispatchState dispatchState =
                spy(new TransitionDispatchState(pending.mClaimed, info));

        boolean handled = mTaskViewTransitions.startAnimation(pending.mClaimed, null,
                dispatchState, mStartTransaction, mFinishTransaction, mFinishCallback);

        Slog.v(TAG, "DispatchState:\n" + dispatchState.getDebugInfo());
        // Has not animated the taskView
        assertWithMessage("Handler should not play the transition")
                .that(handled).isFalse();
        verify(mFinishCallback, never()).onTransitionFinished(any());
        verify(pending.mTaskView, never()).notifyAppeared(anyBoolean());

        // Non task-view spotted as intruder
        verify(dispatchState)
                .addError(eq(mTaskViewTransitions), eq(showingTV), eq(LOST_RELEVANT_CHANGE));
        assertThat(dispatchState.hasErrors(mTaskViewTransitions)).isTrue();
    }

    /**
     * Refactor tests on taskViews
     */