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

Commit dda6e07e authored by Jerry Chang's avatar Jerry Chang
Browse files

Adjust split layout with IME animation in split (1/N)

Update StagePosition to more general SplitPosition so that it could be
shared among split implementations.

Bug: 179262787
Test: atest WMShellUnitTests
Change-Id: I6f461fac62d350f50171136f079cb0254b06d767
parent 3afe697d
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -16,14 +16,14 @@

package com.android.wm.shell;

import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;

import com.android.wm.shell.apppairs.AppPairsController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreenController;

import java.io.PrintWriter;
@@ -145,7 +145,7 @@ public final class ShellCommandHandlerImpl {
        }
        final int taskId = new Integer(args[2]);
        final int sideStagePosition = args.length > 3
                ? new Integer(args[3]) : STAGE_POSITION_BOTTOM_OR_RIGHT;
                ? new Integer(args[3]) : SPLIT_POSITION_BOTTOM_OR_RIGHT;
        mSplitScreenOptional.ifPresent(split -> split.moveToSideStage(taskId, sideStagePosition));
        return true;
    }
+27 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_D
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -42,7 +43,32 @@ import com.android.wm.shell.common.DisplayImeController;
 * Records and handles layout of splits. Helps to calculate proper bounds when configuration or
 * divide position changes.
 */
public class SplitLayout {
public final class SplitLayout {
    /**
     * Split position isn't specified normally meaning to use what ever it is currently set to.
     */
    public static final int SPLIT_POSITION_UNDEFINED = -1;

    /**
     * Specifies that a split is positioned at the top half of the screen if
     * in portrait mode or at the left half of the screen if in landscape mode.
     */
    public static final int SPLIT_POSITION_TOP_OR_LEFT = 0;

    /**
     * Specifies that a split is positioned at the bottom half of the screen if
     * in portrait mode or at the right half of the screen if in landscape mode.
     */
    public static final int SPLIT_POSITION_BOTTOM_OR_RIGHT = 1;

    @IntDef(prefix = {"SPLIT_POSITION_"}, value = {
            SPLIT_POSITION_UNDEFINED,
            SPLIT_POSITION_TOP_OR_LEFT,
            SPLIT_POSITION_BOTTOM_OR_RIGHT
    })
    public @interface SplitPosition {
    }

    private final int mDividerWindowWidth;
    private final int mDividerInsets;
    private final int mDividerSize;
+10 −10
Original line number Diff line number Diff line
@@ -29,14 +29,14 @@ import static android.content.Intent.EXTRA_SHORTCUT_ID;
import static android.content.Intent.EXTRA_TASK_ID;
import static android.content.Intent.EXTRA_USER;

import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;

@@ -64,7 +64,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;

import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.splitscreen.SplitScreen.StagePosition;
import com.android.wm.shell.common.split.SplitLayout.SplitPosition;
import com.android.wm.shell.splitscreen.SplitScreen.StageType;
import com.android.wm.shell.splitscreen.SplitScreenController;

@@ -203,10 +203,10 @@ public class DragAndDropPolicy {
        final boolean leftOrTop = target.type == TYPE_SPLIT_TOP || target.type == TYPE_SPLIT_LEFT;

        @StageType int stage = STAGE_TYPE_UNDEFINED;
        @StagePosition int position = STAGE_POSITION_UNDEFINED;
        @SplitPosition int position = SPLIT_POSITION_UNDEFINED;
        if (target.type != TYPE_FULLSCREEN && mSplitScreen != null) {
            // Update launch options for the split side we are targeting.
            position = leftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT;
            position = leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT;
            if (!inSplitScreen) {
                // Launch in the side stage if we are not in split-screen already.
                stage = STAGE_TYPE_SIDE;
@@ -219,7 +219,7 @@ public class DragAndDropPolicy {
    }

    private void startClipDescription(ClipDescription description, Intent intent,
            @StageType int stage, @StagePosition int position) {
            @StageType int stage, @SplitPosition int position) {
        final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK);
        final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
        final Bundle opts = intent.hasExtra(EXTRA_ACTIVITY_OPTIONS)
@@ -291,12 +291,12 @@ public class DragAndDropPolicy {
     * Interface for actually committing the task launches.
     */
    public interface Starter {
        void startTask(int taskId, @StageType int stage, @StagePosition int position,
        void startTask(int taskId, @StageType int stage, @SplitPosition int position,
                @Nullable Bundle options);
        void startShortcut(String packageName, String shortcutId, @StageType int stage,
                @StagePosition int position, @Nullable Bundle options, UserHandle user);
                @SplitPosition int position, @Nullable Bundle options, UserHandle user);
        void startIntent(PendingIntent intent, Intent fillInIntent,
                @StageType int stage, @StagePosition int position,
                @StageType int stage, @SplitPosition int position,
                @Nullable Bundle options);
        void enterSplitScreen(int taskId, boolean leftOrTop);
        void exitSplitScreen();
+2 −24
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.wm.shell.splitscreen;
import android.annotation.IntDef;

import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.common.split.SplitLayout.SplitPosition;

/**
 * Interface to engage split-screen feature.
@@ -26,29 +27,6 @@ import com.android.wm.shell.common.annotations.ExternalThread;
 */
@ExternalThread
public interface SplitScreen {
    /**
     * Stage position isn't specified normally meaning to use what ever it is currently set to.
     */
    int STAGE_POSITION_UNDEFINED = -1;
    /**
     * Specifies that a stage is positioned at the top half of the screen if
     * in portrait mode or at the left half of the screen if in landscape mode.
     */
    int STAGE_POSITION_TOP_OR_LEFT = 0;

    /**
     * Specifies that a stage is positioned at the bottom half of the screen if
     * in portrait mode or at the right half of the screen if in landscape mode.
     */
    int STAGE_POSITION_BOTTOM_OR_RIGHT = 1;

    @IntDef(prefix = { "STAGE_POSITION_" }, value = {
            STAGE_POSITION_UNDEFINED,
            STAGE_POSITION_TOP_OR_LEFT,
            STAGE_POSITION_BOTTOM_OR_RIGHT
    })
    @interface StagePosition {}

    /**
     * Stage type isn't specified normally meaning to use what ever the default is.
     * E.g. exit split-screen and launch the app in fullscreen.
@@ -75,7 +53,7 @@ public interface SplitScreen {

    /** Callback interface for listening to changes in a split-screen stage. */
    interface SplitScreenListener {
        void onStagePositionChanged(@StageType int stage, @StagePosition int position);
        void onStagePositionChanged(@StageType int stage, @SplitPosition int position);
        void onTaskStageChanged(int taskId, @StageType int stage, boolean visible);
    }

+18 −17
Original line number Diff line number Diff line
@@ -19,9 +19,9 @@ package com.android.wm.shell.splitscreen;
import static android.view.Display.DEFAULT_DISPLAY;

import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_UNDEFINED;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
@@ -53,6 +53,7 @@ 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.annotations.ExternalThread;
import com.android.wm.shell.common.split.SplitLayout.SplitPosition;
import com.android.wm.shell.draganddrop.DragAndDropPolicy;
import com.android.wm.shell.splitscreen.ISplitScreenListener;
import com.android.wm.shell.transition.Transitions;
@@ -122,7 +123,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
        return mStageCoordinator.isSplitScreenVisible();
    }

    public boolean moveToSideStage(int taskId, @SplitScreen.StagePosition int sideStagePosition) {
    public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition) {
        final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
        if (task == null) {
            throw new IllegalArgumentException("Unknown taskId" + taskId);
@@ -131,7 +132,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
    }

    public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
            @SplitScreen.StagePosition int sideStagePosition) {
            @SplitPosition int sideStagePosition) {
        return mStageCoordinator.moveToSideStage(task, sideStagePosition);
    }

@@ -139,7 +140,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
        return mStageCoordinator.removeFromSideStage(taskId);
    }

    public void setSideStagePosition(@SplitScreen.StagePosition int sideStagePosition) {
    public void setSideStagePosition(@SplitPosition int sideStagePosition) {
        mStageCoordinator.setSideStagePosition(sideStagePosition);
    }

@@ -149,7 +150,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,

    public void enterSplitScreen(int taskId, boolean leftOrTop) {
        moveToSideStage(taskId,
                leftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT);
                leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT);
    }

    public void exitSplitScreen() {
@@ -173,7 +174,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
    }

    public void startTask(int taskId, @SplitScreen.StageType int stage,
            @SplitScreen.StagePosition int position, @Nullable Bundle options) {
            @SplitPosition int position, @Nullable Bundle options) {
        options = resolveStartStage(stage, position, options);

        try {
@@ -184,7 +185,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
    }

    public void startShortcut(String packageName, String shortcutId,
            @SplitScreen.StageType int stage, @SplitScreen.StagePosition int position,
            @SplitScreen.StageType int stage, @SplitPosition int position,
            @Nullable Bundle options, UserHandle user) {
        options = resolveStartStage(stage, position, options);

@@ -199,7 +200,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
    }

    public void startIntent(PendingIntent intent, Intent fillInIntent,
            @SplitScreen.StageType int stage, @SplitScreen.StagePosition int position,
            @SplitScreen.StageType int stage, @SplitPosition int position,
            @Nullable Bundle options) {
        options = resolveStartStage(stage, position, options);

@@ -211,11 +212,11 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
    }

    private Bundle resolveStartStage(@SplitScreen.StageType int stage,
            @SplitScreen.StagePosition int position, @Nullable Bundle options) {
            @SplitPosition int position, @Nullable Bundle options) {
        switch (stage) {
            case STAGE_TYPE_UNDEFINED: {
                // Use the stage of the specified position is valid.
                if (position != STAGE_POSITION_UNDEFINED) {
                if (position != SPLIT_POSITION_UNDEFINED) {
                    if (position == mStageCoordinator.getSideStagePosition()) {
                        options = resolveStartStage(STAGE_TYPE_SIDE, position, options);
                    } else {
@@ -228,7 +229,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
                break;
            }
            case STAGE_TYPE_SIDE: {
                if (position != STAGE_POSITION_UNDEFINED) {
                if (position != SPLIT_POSITION_UNDEFINED) {
                    mStageCoordinator.setSideStagePosition(position);
                } else {
                    position = mStageCoordinator.getSideStagePosition();
@@ -240,10 +241,10 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
                break;
            }
            case STAGE_TYPE_MAIN: {
                if (position != STAGE_POSITION_UNDEFINED) {
                if (position != SPLIT_POSITION_UNDEFINED) {
                    // Set the side stage opposite of what we want to the main stage.
                    final int sideStagePosition = position == STAGE_POSITION_TOP_OR_LEFT
                            ? STAGE_POSITION_BOTTOM_OR_RIGHT : STAGE_POSITION_TOP_OR_LEFT;
                    final int sideStagePosition = position == SPLIT_POSITION_TOP_OR_LEFT
                            ? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT;
                    mStageCoordinator.setSideStagePosition(sideStagePosition);
                } else {
                    position = mStageCoordinator.getMainStagePosition();
@@ -418,7 +419,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
        @Override
        public void startTasks(int mainTaskId, @Nullable Bundle mainOptions,
                int sideTaskId, @Nullable Bundle sideOptions,
                @SplitScreen.StagePosition int sidePosition,
                @SplitPosition int sidePosition,
                @Nullable IRemoteTransition remoteTransition) {
            executeRemoteCallWithTaskPermission(mController, "startTasks",
                    (controller) -> controller.mStageCoordinator.startTasks(mainTaskId, mainOptions,
Loading