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

Commit 2bd69d1e authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add adb command to toggle side stage outline border" into sc-v2-dev

parents 6c62e1ce 0b106a92
Loading
Loading
Loading
Loading
+17 −1
Original line number Diff line number Diff line
@@ -103,6 +103,8 @@ public final class ShellCommandHandlerImpl {
                return runMoveToSideStage(args, pw);
            case "removeFromSideStage":
                return runRemoveFromSideStage(args, pw);
            case "setSideStageOutline":
                return runSetSideStageOutline(args, pw);
            case "setSideStagePosition":
                return runSetSideStagePosition(args, pw);
            case "setSideStageVisibility":
@@ -161,6 +163,18 @@ public final class ShellCommandHandlerImpl {
        return true;
    }

    private boolean runSetSideStageOutline(String[] args, PrintWriter pw) {
        if (args.length < 3) {
            // First arguments are "WMShell" and command name.
            pw.println("Error: whether to enable or disable side stage outline border should be"
                    + " provided as arguments");
            return false;
        }
        final boolean enable = new Boolean(args[2]);
        mSplitScreenOptional.ifPresent(split -> split.setSideStageOutline(enable));
        return true;
    }

    private boolean runSetSideStagePosition(String[] args, PrintWriter pw) {
        if (args.length < 3) {
            // First arguments are "WMShell" and command name.
@@ -175,7 +189,7 @@ public final class ShellCommandHandlerImpl {
    private boolean runSetSideStageVisibility(String[] args, PrintWriter pw) {
        if (args.length < 3) {
            // First arguments are "WMShell" and command name.
            pw.println("Error: side stage position should be provided as arguments");
            pw.println("Error: side stage visibility should be provided as arguments");
            return false;
        }
        final Boolean visible = new Boolean(args[2]);
@@ -197,6 +211,8 @@ public final class ShellCommandHandlerImpl {
        pw.println("    Move a task with given id in split-screen mode.");
        pw.println("  removeFromSideStage <taskId>");
        pw.println("    Remove a task with given id in split-screen mode.");
        pw.println("  setSideStageOutline <true/false>");
        pw.println("    Enable/Disable outline on the side-stage.");
        pw.println("  setSideStagePosition <SideStagePosition>");
        pw.println("    Sets the position of the side-stage.");
        pw.println("  setSideStageVisibility <true/false>");
+36 −38
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;

import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
@@ -39,8 +38,6 @@ import android.view.WindowlessWindowManager;

import com.android.wm.shell.R;

import java.util.function.Supplier;

/**
 * Handles drawing outline of the bounds of provided root surface. The outline will be drown with
 * the consideration of display insets like status bar, navigation bar and display cutout.
@@ -48,49 +45,27 @@ import java.util.function.Supplier;
class OutlineManager extends WindowlessWindowManager {
    private static final String WINDOW_NAME = "SplitOutlineLayer";
    private final Context mContext;
    private final int mOutlineColor;
    private final Rect mOutlineBounds = new Rect();
    private final Rect mTmpBounds = new Rect();
    private final Supplier<SurfaceControl> mOutlineSurfaceSupplier;
    private final SurfaceControlViewHost mViewHost;
    private final SurfaceControl mLeash;
    private SurfaceControlViewHost mViewHost;
    private SurfaceControl mHostLeash;
    private SurfaceControl mLeash;
    private int mOutlineColor;

    /**
     * Constructs {@link #OutlineManager} with indicated outline color for the provided root
     * surface.
     */
    OutlineManager(Context context, Configuration configuration,
            Supplier<SurfaceControl> outlineSurfaceSupplier, int color) {
    OutlineManager(Context context, Configuration configuration) {
        super(configuration, null /* rootSurface */, null /* hostInputToken */);
        mContext = context.createWindowContext(context.getDisplay(), TYPE_APPLICATION_OVERLAY,
                null /* options */);
        mOutlineSurfaceSupplier = outlineSurfaceSupplier;
        mOutlineColor = color;

        mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
        final OutlineRoot rootView = (OutlineRoot) LayoutInflater.from(mContext)
                .inflate(R.layout.split_outline, null);
        rootView.updateOutlineBounds(mOutlineBounds, mOutlineColor);

        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                0 /* width */, 0 /* height */, TYPE_APPLICATION_OVERLAY,
                FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT);
        lp.token = new Binder();
        lp.setTitle(WINDOW_NAME);
        lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
        // TODO(b/189839391): Set INPUT_FEATURE_NO_INPUT_CHANNEL after WM supports
        //  TRUSTED_OVERLAY for windowless window without input channel.
        mViewHost.setView(rootView, lp);

        mLeash = getSurfaceControl(mViewHost.getWindowToken());
    }

    @Override
    protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
        b.setParent(mOutlineSurfaceSupplier.get());
        b.setParent(mHostLeash);
    }

    boolean updateOutlineBounds(Rect rootBounds) {
    boolean drawOutlineBounds(Rect rootBounds) {
        if (mLeash == null || mViewHost == null) return false;

        computeOutlineBounds(mContext, rootBounds, mTmpBounds);
        if (mOutlineBounds.equals(mTmpBounds)) {
            return false;
@@ -107,9 +82,32 @@ class OutlineManager extends WindowlessWindowManager {
        return true;
    }

    @Nullable
    SurfaceControl getLeash() {
        return mLeash;
    void inflate(SurfaceControl.Transaction t, SurfaceControl hostLeash, int color) {
        if (mLeash != null || mViewHost != null) return;

        mHostLeash = hostLeash;
        mOutlineColor = color;
        mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
        final OutlineRoot rootView = (OutlineRoot) LayoutInflater.from(mContext)
                .inflate(R.layout.split_outline, null);

        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                0 /* width */, 0 /* height */, TYPE_APPLICATION_OVERLAY,
                FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT);
        lp.token = new Binder();
        lp.setTitle(WINDOW_NAME);
        lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
        // TODO(b/189839391): Set INPUT_FEATURE_NO_INPUT_CHANNEL after WM supports
        //  TRUSTED_OVERLAY for windowless window without input channel.
        mViewHost.setView(rootView, lp);
        mLeash = getSurfaceControl(mViewHost.getWindowToken());
        t.setLayer(mLeash, Integer.MAX_VALUE);
    }

    void release() {
        if (mViewHost != null) {
            mViewHost.release();
        }
    }

    private static void computeOutlineBounds(Context context, Rect rootBounds, Rect outBounds) {
+20 −28
Original line number Diff line number Diff line
@@ -21,12 +21,10 @@ import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;

import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.SyncTransactionQueue;

@@ -48,20 +46,12 @@ class SideStage extends StageTaskListener {
        mContext = context;
    }

    @VisibleForTesting
    SideStage(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
            StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
            SurfaceSession surfaceSession, OutlineManager outlineManager) {
        this(context, taskOrganizer, displayId, callbacks, syncQueue, surfaceSession);
        mOutlineManager = outlineManager;
    }

    void addTask(ActivityManager.RunningTaskInfo task, Rect rootBounds,
            WindowContainerTransaction wct) {
        final WindowContainerToken rootToken = mRootTaskInfo.token;
        wct.setBounds(rootToken, rootBounds)
                .reparent(task.token, rootToken, true /* onTop*/)
                // Moving the root task to top after the child tasks were repareted , or the root
                // Moving the root task to top after the child tasks were reparented , or the root
                // task cannot be visible and focused.
                .reorder(rootToken, true /* onTop */);
    }
@@ -87,31 +77,33 @@ class SideStage extends StageTaskListener {
        return true;
    }

    @Override
    @CallSuper
    public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
        super.onTaskAppeared(taskInfo, leash);
        if (mRootTaskInfo != null && mRootTaskInfo.taskId == taskInfo.taskId
                && mOutlineManager == null) {
            mOutlineManager = new OutlineManager(mContext, mRootTaskInfo.configuration,
                    () -> mRootLeash,
                    Color.YELLOW);
            if (mOutlineManager.getLeash() != null) {
                mSyncQueue.runInSync(t -> {
                    t.setLayer(mOutlineManager.getLeash(), Integer.MAX_VALUE);
                });
    void enableOutline(boolean enable) {
        if (enable) {
            if (mOutlineManager == null && mRootTaskInfo != null) {
                mOutlineManager = new OutlineManager(mContext, mRootTaskInfo.configuration);
                mSyncQueue.runInSync(t -> mOutlineManager.inflate(t, mRootLeash, Color.YELLOW));
                updateOutlineBounds();
            }
        } else {
            if (mOutlineManager != null) {
                mOutlineManager.release();
                mOutlineManager = null;
            }
        }
    }

    private void updateOutlineBounds() {
        if (mOutlineManager == null || mRootTaskInfo == null || !mRootTaskInfo.isVisible) return;
        mOutlineManager.drawOutlineBounds(
                mRootTaskInfo.configuration.windowConfiguration.getBounds());
    }

    @Override
    @CallSuper
    public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
        super.onTaskInfoChanged(taskInfo);
        if (mRootTaskInfo != null && mRootTaskInfo.taskId == taskInfo.taskId
                && mRootTaskInfo.isRunning) {
            mOutlineManager.updateOutlineBounds(
                    mRootTaskInfo.configuration.windowConfiguration.getBounds());
        if (mRootTaskInfo != null && mRootTaskInfo.taskId == taskInfo.taskId) {
            updateOutlineBounds();
        }
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -142,6 +142,10 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
        return mStageCoordinator.removeFromSideStage(taskId);
    }

    public void setSideStageOutline(boolean enable) {
        mStageCoordinator.setSideStageOutline(enable);
    }

    public void setSideStagePosition(@SplitPosition int sideStagePosition) {
        mStageCoordinator.setSideStagePosition(sideStagePosition);
    }
+4 −0
Original line number Diff line number Diff line
@@ -232,6 +232,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        return result;
    }

    void setSideStageOutline(boolean enable) {
        mSideStage.enableOutline(enable);
    }

    /** Starts 2 tasks in one transition. */
    void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId,
            @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
Loading