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

Commit 953d3b1e authored by Jorge Gil's avatar Jorge Gil
Browse files

Add bounding rects to the captionBar() inset source

In desktop mode, the caption used for freeform windows has a big space
of empty space between the app chip and the window control buttons.
To allow apps to utilize that empty space, this CL reports the chip
and control btns as bounding rects to the inset system, so that apps
can avoid overlapping with them when drawing e2e behind the caption bar.

Bug: 316387515
Test: m
Change-Id: Id7261e4a3996628079068db23b5d68cbafe79c0e
parent e2ee483b
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -435,6 +435,9 @@
         Text varies in size, we will calculate that width separately. -->
    <dimen name="desktop_mode_app_details_width_minus_text">62dp</dimen>

    <!-- 22dp padding + 24dp app icon + 16dp expand button + 86dp text (max) -->
    <dimen name="desktop_mode_app_details_max_width">148dp</dimen>

    <!-- The width of the maximize menu in desktop mode. -->
    <dimen name="desktop_mode_maximize_menu_width">287dp</dimen>

+24 −2
Original line number Diff line number Diff line
@@ -299,12 +299,34 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
            ActivityManager.RunningTaskInfo taskInfo,
            boolean applyStartTransactionOnDraw,
            boolean shouldSetTaskPositionAndCrop) {
        final int captionLayoutId = getDesktopModeWindowDecorLayoutId(taskInfo.getWindowingMode());
        relayoutParams.reset();
        relayoutParams.mRunningTaskInfo = taskInfo;
        relayoutParams.mLayoutResId =
            getDesktopModeWindowDecorLayoutId(taskInfo.getWindowingMode());
        relayoutParams.mLayoutResId = captionLayoutId;
        relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode());
        relayoutParams.mCaptionWidthId = getCaptionWidthId(relayoutParams.mLayoutResId);

        // The "app controls" type caption bar should report the occluding elements as bounding
        // rects to the insets system so that apps can draw in the empty space left in the center.
        if (captionLayoutId == R.layout.desktop_mode_app_controls_window_decor) {
            // The "app chip" section of the caption bar, it's aligned to the left and its width
            // varies depending on the length of the app name, but we'll report its max width for
            // now.
            // TODO(b/316387515): consider reporting the true width after it's been laid out.
            final RelayoutParams.OccludingCaptionElement appChipElement =
                    new RelayoutParams.OccludingCaptionElement();
            appChipElement.mWidthResId = R.dimen.desktop_mode_app_details_max_width;
            appChipElement.mAlignment = RelayoutParams.OccludingCaptionElement.Alignment.START;
            relayoutParams.mOccludingCaptionElements.add(appChipElement);
            // The "controls" section of the caption bar (maximize, close btns). These are aligned
            // to the right of the caption bar and have a fixed width.
            // TODO(b/316387515): add additional padding for an exclusive drag-move region.
            final RelayoutParams.OccludingCaptionElement controlsElement =
                    new RelayoutParams.OccludingCaptionElement();
            controlsElement.mWidthResId = R.dimen.desktop_mode_right_edge_buttons_width;
            controlsElement.mAlignment = RelayoutParams.OccludingCaptionElement.Alignment.END;
            relayoutParams.mOccludingCaptionElements.add(controlsElement);
        }
        if (DesktopModeStatus.useWindowShadow(/* isFocusedWindow= */ taskInfo.isFocused)) {
            relayoutParams.mShadowRadiusId = taskInfo.isFocused
                    ? R.dimen.freeform_decor_shadow_focused_thickness
+61 −6
Original line number Diff line number Diff line
@@ -50,7 +50,10 @@ import android.window.WindowContainerTransaction;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.desktopmode.DesktopModeStatus;
import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams.OccludingCaptionElement;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

/**
@@ -293,13 +296,36 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
            outResult.mRootView.setTaskFocusState(mTaskInfo.isFocused);

            // Caption insets
            mCaptionInsetsRect.set(taskBounds);
            if (mIsCaptionVisible) {
                mCaptionInsetsRect.bottom =
                        mCaptionInsetsRect.top + outResult.mCaptionHeight;
                // Caption inset is the full width of the task with the |captionHeight| and
                // positioned at the top of the task bounds, also in absolute coordinates.
                // So just reuse the task bounds and adjust the bottom coordinate.
                mCaptionInsetsRect.set(taskBounds);
                mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + outResult.mCaptionHeight;

                // Caption bounding rectangles: these are optional, and are used to present finer
                // insets than traditional |Insets| to apps about where their content is occluded.
                // These are also in absolute coordinates.
                final Rect[] boundingRects;
                final int numOfElements = params.mOccludingCaptionElements.size();
                if (numOfElements == 0) {
                    boundingRects = null;
                } else {
                    boundingRects = new Rect[numOfElements];
                    for (int i = 0; i < numOfElements; i++) {
                        final OccludingCaptionElement element =
                                params.mOccludingCaptionElements.get(i);
                        final int elementWidthPx =
                                resources.getDimensionPixelSize(element.mWidthResId);
                        boundingRects[i] =
                                calculateBoundingRect(element, elementWidthPx, mCaptionInsetsRect);
                    }
                }

                // Add this caption as an inset source.
                wct.addInsetsSource(mTaskInfo.token,
                        mOwner, 0 /* index */, WindowInsets.Type.captionBar(), mCaptionInsetsRect,
                        null /* boundingRects */);
                        boundingRects);
                wct.addInsetsSource(mTaskInfo.token,
                        mOwner, 0 /* index */, WindowInsets.Type.mandatorySystemGestures(),
                        mCaptionInsetsRect, null /* boundingRects */);
@@ -378,6 +404,20 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
        }
    }

    private Rect calculateBoundingRect(@NonNull OccludingCaptionElement element,
            int elementWidthPx, @NonNull Rect captionRect) {
        switch (element.mAlignment) {
            case START -> {
                return new Rect(0, 0, elementWidthPx, captionRect.height());
            }
            case END -> {
                return new Rect(captionRect.width() - elementWidthPx, 0,
                        captionRect.width(), captionRect.height());
            }
        }
        throw new IllegalArgumentException("Unexpected alignment " + element.mAlignment);
    }

    /**
     * Checks if task has entered/exited immersive mode and requires a change in caption visibility.
     */
@@ -555,8 +595,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
        int mLayoutResId;
        int mCaptionHeightId;
        int mCaptionWidthId;
        int mShadowRadiusId;
        final List<OccludingCaptionElement> mOccludingCaptionElements = new ArrayList<>();

        int mShadowRadiusId;
        int mCornerRadius;

        Configuration mWindowDecorConfig;
@@ -568,14 +609,28 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
            mLayoutResId = Resources.ID_NULL;
            mCaptionHeightId = Resources.ID_NULL;
            mCaptionWidthId = Resources.ID_NULL;
            mShadowRadiusId = Resources.ID_NULL;
            mOccludingCaptionElements.clear();

            mShadowRadiusId = Resources.ID_NULL;
            mCornerRadius = 0;

            mApplyStartTransactionOnDraw = false;
            mSetTaskPositionAndCrop = false;
            mWindowDecorConfig = null;
        }

        /**
         * Describes elements within the caption bar that could occlude app content, and should be
         * sent as bounding rectangles to the insets system.
         */
        static class OccludingCaptionElement {
            int mWidthResId;
            Alignment mAlignment;

            enum Alignment {
                START, END
            }
        }
    }

    static class RelayoutResult<T extends View & TaskFocusStateConsumer> {