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

Commit d448dc23 authored by Jerry Chang's avatar Jerry Chang Committed by Android (Google) Code Review
Browse files

Merge "Integrate launch-to-side split transition to shell transition"

parents 4fb303c5 1b560d87
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -318,8 +318,15 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
            startIntentLegacy(intent, fillInIntent, position, options);
            return;
        }
        mStageCoordinator.startIntent(intent, fillInIntent, STAGE_TYPE_UNDEFINED, position, options,
                null /* remote */);

        try {
            options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options,
                    null /* wct */);
            intent.send(mContext, 0, fillInIntent, null /* onFinished */, null /* handler */,
                    null /* requiredPermission */, options);
        } catch (PendingIntent.CanceledException e) {
            Slog.e(TAG, "Failed to launch task", e);
        }
    }

    private void startIntentLegacy(PendingIntent intent, Intent fillInIntent,
+47 −66
Original line number Diff line number Diff line
@@ -44,7 +44,6 @@ import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonT
import static com.android.wm.shell.splitscreen.SplitScreenTransitions.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS_SNAP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
import static com.android.wm.shell.transition.Transitions.isClosingType;
import static com.android.wm.shell.transition.Transitions.isOpeningType;
@@ -54,10 +53,8 @@ import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.app.WindowConfiguration;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.hardware.devicestate.DeviceStateManager;
import android.os.Bundle;
@@ -436,17 +433,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        mTaskOrganizer.applyTransaction(wct);
    }

    public void startIntent(PendingIntent intent, Intent fillInIntent,
            @StageType int stage, @SplitPosition int position,
            @androidx.annotation.Nullable Bundle options,
            @Nullable RemoteTransition remoteTransition) {
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        options = resolveStartStage(stage, position, options, wct);
        wct.sendPendingIntent(intent, fillInIntent, options);
        mSplitTransitions.startEnterTransition(
                TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct, remoteTransition, this);
    }

    /**
     * Collects all the current child tasks of a specific split and prepares transaction to evict
     * them to display.
@@ -1158,12 +1144,14 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                mSplitTransitions.mPendingDismiss = transition;
            }
        } else {
            // Not in split mode, so look for an open into a split stage just so we can whine and
            // complain about how this isn't a supported operation.
            // Not in split mode, so look for an open into a split stage to active split screen.
            if ((type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT)) {
                if (getStageOfTask(triggerTask) != null) {
                    throw new IllegalStateException("Entering split implicitly with only one task"
                            + " isn't supported.");
                    // One task is appearing in split, prepare to enter split screen.
                    out = new WindowContainerTransaction();
                    mSplitTransitions.mPendingEnter = transition;
                    mMainStage.activate(getMainStageBounds(), out, true /* includingTopTask */);
                    mSideStage.moveToTop(getSideStageBounds(), out);
                }
            }
        }
@@ -1232,8 +1220,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,

    private boolean startPendingEnterAnimation(@NonNull IBinder transition,
            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) {
        if (info.getType() == TRANSIT_SPLIT_SCREEN_PAIR_OPEN) {
            // First, verify that we actually have opened 2 apps in split.
        // First, verify that we actually have opened apps in both splits.
        TransitionInfo.Change mainChild = null;
        TransitionInfo.Change sideChild = null;
        for (int iC = 0; iC < info.getChanges().size(); ++iC) {
@@ -1256,8 +1243,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,

        // Update local states (before animating).
        setDividerVisibility(true);
            setSideStagePosition(SPLIT_POSITION_BOTTOM_OR_RIGHT, false /* updateBounds */,
                    null /* wct */);
        setSplitsVisible(true);

        addDividerBarToTransition(info, t, true /* show */);
@@ -1279,10 +1264,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                    + " before startAnimation().");
        }
        return true;
        } else {
            // TODO: other entry method animations
            throw new RuntimeException("Unsupported split-entry");
        }
    }

    private boolean startPendingDismissAnimation(@NonNull IBinder transition,
+51 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ 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 android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;

import static com.android.wm.shell.splitscreen.SplitTestUtils.createMockSurface;
import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
@@ -66,7 +67,6 @@ import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.transition.Transitions;

import org.junit.Before;
@@ -132,6 +132,40 @@ public class SplitTransitionTests extends ShellTestCase {
                .setParentTaskId(mSideStage.mRootTaskInfo.taskId).build();
    }

    @Test
    public void testLaunchToSide() {
        ActivityManager.RunningTaskInfo newTask = new TestRunningTaskInfoBuilder()
                .setParentTaskId(mSideStage.mRootTaskInfo.taskId).build();
        ActivityManager.RunningTaskInfo reparentTask = new TestRunningTaskInfoBuilder()
                .setParentTaskId(mMainStage.mRootTaskInfo.taskId).build();

        // Create a request to start a new task in side stage
        TransitionRequestInfo request = new TransitionRequestInfo(TRANSIT_TO_FRONT, newTask, null);
        IBinder transition = mock(IBinder.class);
        WindowContainerTransaction result =
                mStageCoordinator.handleRequest(transition, request);

        // it should handle the transition to enter split screen.
        assertNotNull(result);
        assertTrue(containsSplitEnter(result));

        // simulate the transition
        TransitionInfo.Change openChange = createChange(TRANSIT_OPEN, newTask);
        TransitionInfo.Change reparentChange = createChange(TRANSIT_CHANGE, reparentTask);

        TransitionInfo info = new TransitionInfo(TRANSIT_TO_FRONT, 0);
        info.addChange(openChange);
        info.addChange(reparentChange);
        mSideStage.onTaskAppeared(newTask, createMockSurface());
        mMainStage.onTaskAppeared(reparentTask, createMockSurface());
        boolean accepted = mStageCoordinator.startAnimation(transition, info,
                mock(SurfaceControl.Transaction.class),
                mock(SurfaceControl.Transaction.class),
                mock(Transitions.TransitionFinishCallback.class));
        assertTrue(accepted);
        assertTrue(mStageCoordinator.isSplitScreenVisible());
    }

    @Test
    public void testLaunchPair() {
        TransitionInfo info = createEnterPairInfo();
@@ -324,6 +358,22 @@ public class SplitTransitionTests extends ShellTestCase {
                true /* includingTopTask */);
    }

    private boolean containsSplitEnter(@NonNull WindowContainerTransaction wct) {
        boolean movedMainToFront = false;
        boolean movedSideToFront = false;
        for (int i = 0; i < wct.getHierarchyOps().size(); ++i) {
            WindowContainerTransaction.HierarchyOp op = wct.getHierarchyOps().get(i);
            if (op.getType() == HIERARCHY_OP_TYPE_REORDER) {
                if (op.getContainer() == mMainStage.mRootTaskInfo.token.asBinder()) {
                    movedMainToFront = true;
                } else if (op.getContainer() == mSideStage.mRootTaskInfo.token.asBinder()) {
                    movedSideToFront = true;
                }
            }
        }
        return movedMainToFront && movedSideToFront;
    }

    private boolean containsSplitExit(@NonNull WindowContainerTransaction wct) {
        // reparenting of child tasks to null constitutes exiting split.
        boolean reparentedMain = false;
+2 −1
Original line number Diff line number Diff line
@@ -1672,7 +1672,8 @@ class ActivityStarter {
                }
                if (newTransition != null) {
                    transitionController.requestStartTransition(newTransition,
                            mTargetTask, remoteTransition, null /* displayChange */);
                            mTargetTask == null ? r.getTask() : mTargetTask,
                            remoteTransition, null /* displayChange */);
                } else if (started) {
                    // Make the collecting transition wait until this request is ready.
                    transitionController.setReady(r, false);