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

Commit 707fb0fb authored by Wale Ogunwale's avatar Wale Ogunwale Committed by Jerry Chang
Browse files

Baseline support for main/side stage split-screen model

Bug: 175416931
Test: atest StageCoordinatorTests StageTaskListenerTests
Test: atest MainStageTests SideStageTests
Change-Id: Ib5f000599d09d6a07b559aa8a06e5786541f2324
parent 83010aa4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -111,6 +111,7 @@ public class RootTaskDisplayAreaOrganizer extends DisplayAreaOrganizer {
        }

        mDisplayAreasInfo.put(displayId, displayAreaInfo);
        mLeashes.put(displayId, leash);

        ArrayList<RootTaskDisplayAreaListener> listeners = mListeners.get(displayId);
        if (listeners != null) {
+39 −6
Original line number Diff line number Diff line
@@ -16,18 +16,16 @@

package com.android.wm.shell;

import android.util.Slog;

import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.splitscreen.SplitScreen;

import java.io.PrintWriter;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * An entry point into the shell for dumping shell internal state and running adb commands.
@@ -38,6 +36,7 @@ public final class ShellCommandHandlerImpl {
    private static final String TAG = ShellCommandHandlerImpl.class.getSimpleName();

    private final Optional<LegacySplitScreen> mLegacySplitScreenOptional;
    private final Optional<SplitScreen> mSplitScreenOptional;
    private final Optional<Pip> mPipOptional;
    private final Optional<OneHanded> mOneHandedOptional;
    private final Optional<HideDisplayCutout> mHideDisplayCutout;
@@ -49,19 +48,21 @@ public final class ShellCommandHandlerImpl {
    public static ShellCommandHandler create(
            ShellTaskOrganizer shellTaskOrganizer,
            Optional<LegacySplitScreen> legacySplitScreenOptional,
            Optional<SplitScreen> splitScreenOptional,
            Optional<Pip> pipOptional,
            Optional<OneHanded> oneHandedOptional,
            Optional<HideDisplayCutout> hideDisplayCutout,
            Optional<AppPairs> appPairsOptional,
            ShellExecutor mainExecutor) {
        return new ShellCommandHandlerImpl(shellTaskOrganizer, legacySplitScreenOptional,
                pipOptional, oneHandedOptional, hideDisplayCutout, appPairsOptional,
                mainExecutor).mImpl;
                splitScreenOptional, pipOptional, oneHandedOptional, hideDisplayCutout,
                appPairsOptional, mainExecutor).mImpl;
    }

    private ShellCommandHandlerImpl(
            ShellTaskOrganizer shellTaskOrganizer,
            Optional<LegacySplitScreen> legacySplitScreenOptional,
            Optional<SplitScreen> splitScreenOptional,
            Optional<Pip> pipOptional,
            Optional<OneHanded> oneHandedOptional,
            Optional<HideDisplayCutout> hideDisplayCutout,
@@ -69,6 +70,7 @@ public final class ShellCommandHandlerImpl {
            ShellExecutor mainExecutor) {
        mShellTaskOrganizer = shellTaskOrganizer;
        mLegacySplitScreenOptional = legacySplitScreenOptional;
        mSplitScreenOptional = splitScreenOptional;
        mPipOptional = pipOptional;
        mOneHandedOptional = oneHandedOptional;
        mHideDisplayCutout = hideDisplayCutout;
@@ -88,6 +90,9 @@ public final class ShellCommandHandlerImpl {
        pw.println();
        pw.println();
        mAppPairsOptional.ifPresent(appPairs -> appPairs.dump(pw, ""));
        pw.println();
        pw.println();
        mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.dump(pw, ""));
    }


@@ -102,6 +107,10 @@ public final class ShellCommandHandlerImpl {
                return runPair(args, pw);
            case "unpair":
                return runUnpair(args, pw);
            case "pinTask":
                return runPinTask(args, pw);
            case "unpinTask":
                return runUnpinTask(args, pw);
            case "help":
                return runHelp(pw);
            default:
@@ -109,7 +118,6 @@ public final class ShellCommandHandlerImpl {
        }
    }


    private boolean runPair(String[] args, PrintWriter pw) {
        if (args.length < 4) {
            // First two arguments are "WMShell" and command name.
@@ -133,6 +141,28 @@ public final class ShellCommandHandlerImpl {
        return true;
    }

    private boolean runPinTask(String[] args, PrintWriter pw) {
        if (args.length < 3) {
            // First arguments are "WMShell" and command name.
            pw.println("Error: task id should be provided as arguments");
            return false;
        }
        final int taskId = new Integer(args[2]);
        mSplitScreenOptional.ifPresent(split -> split.pinTask(taskId));
        return true;
    }

    private boolean runUnpinTask(String[] args, PrintWriter pw) {
        if (args.length < 3) {
            // First arguments are "WMShell" and command name.
            pw.println("Error: task id should be provided as arguments");
            return false;
        }
        final int taskId = new Integer(args[2]);
        mSplitScreenOptional.ifPresent(split -> split.unpinTask(taskId));
        return true;
    }

    private boolean runHelp(PrintWriter pw) {
        pw.println("Window Manager Shell commands:");
        pw.println("  help");
@@ -142,6 +172,9 @@ public final class ShellCommandHandlerImpl {
        pw.println("  pair <taskId1> <taskId2>");
        pw.println("  unpair <taskId>");
        pw.println("    Pairs/unpairs tasks with given ids.");
        pw.println("  pinTask <taskId>");
        pw.println("  unpinTask <taskId>");
        pw.println("    Pin/Unpin a task with given id in split-screen mode.");
        return true;
    }

+7 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.transition.Transitions;

import java.util.Optional;
@@ -38,6 +39,7 @@ public class ShellInitImpl {
    private final DragAndDropController mDragAndDropController;
    private final ShellTaskOrganizer mShellTaskOrganizer;
    private final Optional<LegacySplitScreen> mLegacySplitScreenOptional;
    private final Optional<SplitScreen> mSplitScreenOptional;
    private final Optional<AppPairs> mAppPairsOptional;
    private final FullscreenTaskListener mFullscreenTaskListener;
    private final ShellExecutor mMainExecutor;
@@ -49,6 +51,7 @@ public class ShellInitImpl {
            DragAndDropController dragAndDropController,
            ShellTaskOrganizer shellTaskOrganizer,
            Optional<LegacySplitScreen> legacySplitScreenOptional,
            Optional<SplitScreen> splitScreenOptional,
            Optional<AppPairs> appPairsOptional,
            FullscreenTaskListener fullscreenTaskListener,
            Transitions transitions,
@@ -57,6 +60,7 @@ public class ShellInitImpl {
                dragAndDropController,
                shellTaskOrganizer,
                legacySplitScreenOptional,
                splitScreenOptional,
                appPairsOptional,
                fullscreenTaskListener,
                transitions,
@@ -67,6 +71,7 @@ public class ShellInitImpl {
            DragAndDropController dragAndDropController,
            ShellTaskOrganizer shellTaskOrganizer,
            Optional<LegacySplitScreen> legacySplitScreenOptional,
            Optional<SplitScreen> splitScreenOptional,
            Optional<AppPairs> appPairsOptional,
            FullscreenTaskListener fullscreenTaskListener,
            Transitions transitions,
@@ -75,6 +80,7 @@ public class ShellInitImpl {
        mDragAndDropController = dragAndDropController;
        mShellTaskOrganizer = shellTaskOrganizer;
        mLegacySplitScreenOptional = legacySplitScreenOptional;
        mSplitScreenOptional = splitScreenOptional;
        mAppPairsOptional = appPairsOptional;
        mFullscreenTaskListener = fullscreenTaskListener;
        mTransitions = transitions;
@@ -91,6 +97,7 @@ public class ShellInitImpl {
        mShellTaskOrganizer.registerOrganizer();

        mAppPairsOptional.ifPresent(AppPairs::onOrganizerRegistered);
        mSplitScreenOptional.ifPresent(SplitScreen::onOrganizerRegistered);

        // Bind the splitscreen impl to the drag drop controller
        mDragAndDropController.initialize(mLegacySplitScreenOptional);
+10 −9
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.LayoutChan

        mTaskInfo1 = task1;
        mTaskInfo2 = task2;
        mSplitLayout = new SplitLayout(
        mSplitLayout = new SplitLayout(TAG + "SplitDivider",
                mDisplayController.getDisplayContext(mRootTaskInfo.displayId),
                mRootTaskInfo.configuration, this /* layoutChangeListener */,
                b -> b.setParent(mRootTaskLeash));
@@ -248,13 +248,13 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.LayoutChan
        final Rect bounds1 = layout.getBounds1();
        final Rect bounds2 = layout.getBounds2();
        mSyncQueue.runInSync(t -> t
                // Ignores the original surface bounds so that the app could fill up the gap
                // between each surface with corresponding background while resizing.
                .setWindowCrop(mTaskLeash1, bounds1.width(), bounds1.height())
                .setWindowCrop(mTaskLeash2, bounds2.width(), bounds2.height())
                .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
                .setPosition(mTaskLeash1, bounds1.left, bounds1.top)
                .setPosition(mTaskLeash2, bounds2.left, bounds2.top));
                .setPosition(mTaskLeash2, bounds2.left, bounds2.top)
                // Sets crop to prevent visible region of tasks overlap with each other when
                // re-positioning surfaces while resizing.
                .setWindowCrop(mTaskLeash1, bounds1.width(), bounds1.height())
                .setWindowCrop(mTaskLeash2, bounds2.width(), bounds2.height()));
    }

    @Override
@@ -271,10 +271,11 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.LayoutChan
        mSyncQueue.runInSync(t -> t
                // Resets layer of divider bar to make sure it is always on top.
                .setLayer(dividerLeash, Integer.MAX_VALUE)
                .setWindowCrop(mTaskLeash1, bounds1.width(), bounds1.height())
                .setWindowCrop(mTaskLeash2, bounds2.width(), bounds2.height())
                .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
                .setPosition(mTaskLeash1, bounds1.left, bounds1.top)
                .setPosition(mTaskLeash2, bounds2.left, bounds2.top));
                .setPosition(mTaskLeash2, bounds2.left, bounds2.top)
                // Resets crop to apply new surface bounds directly.
                .setWindowCrop(mTaskLeash1, null)
                .setWindowCrop(mTaskLeash2, null));
    }
}
+21 −6
Original line number Diff line number Diff line
@@ -55,14 +55,15 @@ public class SplitLayout {
    private Context mContext;
    private DividerSnapAlgorithm mDividerSnapAlgorithm;
    private int mDividePosition;
    private boolean mInitialized = false;

    public SplitLayout(Context context, Configuration configuration,
    public SplitLayout(String windowName, Context context, Configuration configuration,
            LayoutChangeListener layoutChangeListener,
            SplitWindowManager.ParentContainerCallbacks parentContainerCallbacks) {
        mContext = context.createConfigurationContext(configuration);
        mLayoutChangeListener = layoutChangeListener;
        mSplitWindowManager = new SplitWindowManager(
                mContext, configuration, parentContainerCallbacks);
                windowName, mContext, configuration, parentContainerCallbacks);

        mDividerWindowWidth = context.getResources().getDimensionPixelSize(
                com.android.internal.R.dimen.docked_stack_divider_thickness);
@@ -72,8 +73,7 @@ public class SplitLayout {

        mRootBounds.set(configuration.windowConfiguration.getBounds());
        mDividerSnapAlgorithm = getSnapAlgorithm(context.getResources(), mRootBounds);
        mDividePosition = mDividerSnapAlgorithm.getMiddleTarget().position;
        updateBounds(mDividePosition);
        resetDividerPosition();
    }

    /** Gets bounds of the primary split. */
@@ -112,8 +112,13 @@ public class SplitLayout {
        mSplitWindowManager.setConfiguration(configuration);
        mRootBounds.set(rootBounds);
        mDividerSnapAlgorithm = getSnapAlgorithm(mContext.getResources(), mRootBounds);
        mDividePosition = mDividerSnapAlgorithm.getMiddleTarget().position;
        updateBounds(mDividePosition);
        resetDividerPosition();

        // Don't inflate divider bar if it is not initialized.
        if (!mInitialized) {
            return false;
        }

        release();
        init();
        return true;
@@ -141,11 +146,15 @@ public class SplitLayout {

    /** Inflates {@link DividerView} on the root surface. */
    public void init() {
        if (mInitialized) return;
        mInitialized = true;
        mSplitWindowManager.init(this);
    }

    /** Releases the surface holding the current {@link DividerView}. */
    public void release() {
        if (!mInitialized) return;
        mInitialized = false;
        mSplitWindowManager.release();
    }

@@ -166,6 +175,12 @@ public class SplitLayout {
        mSplitWindowManager.setResizingSplits(false);
    }

    /** Resets divider position. */
    public void resetDividerPosition() {
        mDividePosition = mDividerSnapAlgorithm.getMiddleTarget().position;
        updateBounds(mDividePosition);
    }

    /**
     * Sets new divide position and updates bounds correspondingly. Notifies listener if the new
     * target indicates dismissing split.
Loading