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

Commit b4700f10 authored by Jorge Gil's avatar Jorge Gil
Browse files

[2/N] (Handle Menu) Better encapsulation of window decor's views

Moves click detection out of the DesktopModeWindowDecorViewModel
and into the HandleMenuView.

The goal here is to keep implementation details of the menu view
encapsulated (resource ids, gesture detection, styling, etc), and
provide the decoration/viewmodel with abstractions for actions taken by
the user on the view (e.g. #setOnToDesktopClickListener).

Flag: EXEMPT refactor
Bug: 346441962
Test: with additional view container flag enabled & disabled - check
HandleMenu works as usual (clicks, animations, fullscreen/freeform)
Test: atest WMShellUnitTests

Change-Id: I003c0d5cc042dd9a53c6f1800a8191cd84dc2b87
parent bdf97469
Loading
Loading
Loading
Loading
+90 −56
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_HOVER_ENTER;
import static android.view.MotionEvent.ACTION_HOVER_EXIT;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_OUTSIDE;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.WindowInsets.Type.statusBars;

@@ -118,6 +117,8 @@ import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionReg
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder;

import kotlin.Unit;

import java.io.PrintWriter;
import java.util.Optional;
import java.util.function.Supplier;
@@ -418,13 +419,13 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
        mWindowDecorByTaskId.remove(taskInfo.taskId);
    }

    private void onMaximizeOrRestore(int taskId, String tag) {
    private void onMaximizeOrRestore(int taskId, String source) {
        final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId);
        if (decoration == null) {
            return;
        }
        mInteractionJankMonitor.begin(
                decoration.mTaskSurface, mContext, Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, tag);
                decoration.mTaskSurface, mContext, Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, source);
        mDesktopTasksController.toggleDesktopTaskSize(decoration.mTaskInfo);
        decoration.closeHandleMenu();
        decoration.closeMaximizeMenu();
@@ -441,10 +442,14 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
        decoration.closeMaximizeMenu();
    }

    private void onOpenInBrowser(@NonNull DesktopModeWindowDecoration decor, @NonNull Uri uri) {
    private void onOpenInBrowser(int taskId, @NonNull Uri uri) {
        final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId);
        if (decoration == null) {
            return;
        }
        openInBrowser(uri);
        decor.closeHandleMenu();
        decor.closeMaximizeMenu();
        decoration.closeHandleMenu();
        decoration.closeMaximizeMenu();
    }

    private void openInBrowser(Uri uri) {
@@ -454,6 +459,57 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
        mContext.startActivity(intent);
    }

    private void onToDesktop(int taskId, DesktopModeTransitionSource source) {
        final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId);
        if (decoration == null) {
            return;
        }
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext,
                CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU);
        // App sometimes draws before the insets from WindowDecoration#relayout have
        // been added, so they must be added here
        decoration.addCaptionInset(wct);
        mDesktopTasksController.moveTaskToDesktop(taskId, wct, source);
        decoration.closeHandleMenu();
    }

    private void onToFullscreen(int taskId) {
        final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId);
        if (decoration == null) {
            return;
        }
        decoration.closeHandleMenu();
        if (isTaskInSplitScreen(taskId)) {
            mSplitScreenController.moveTaskToFullscreen(taskId,
                    SplitScreenController.EXIT_REASON_DESKTOP_MODE);
        } else {
            mDesktopTasksController.moveToFullscreen(taskId,
                    DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON);
        }
    }

    private void onToSplitScreen(int taskId) {
        final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId);
        if (decoration == null) {
            return;
        }
        decoration.closeHandleMenu();
        // When the app enters split-select, the handle will no longer be visible, meaning
        // we shouldn't receive input for it any longer.
        decoration.disposeStatusBarInputLayer();
        mDesktopTasksController.requestSplit(decoration.mTaskInfo, false /* leftOrTop */);
    }

    private void onNewWindow(int taskId) {
        final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId);
        if (decoration == null) {
            return;
        }
        decoration.closeHandleMenu();
        mDesktopTasksController.openNewWindow(decoration.mTaskInfo);
    }

    private class DesktopModeTouchEventListener extends GestureDetector.SimpleOnGestureListener
            implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener,
            View.OnGenericMotionListener, DragDetector.MotionEventHandler {
@@ -511,40 +567,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                    moveTaskToFront(decoration.mTaskInfo);
                    decoration.createHandleMenu(mSplitScreenController);
                }
            } else if (id == R.id.desktop_button) {
                final WindowContainerTransaction wct = new WindowContainerTransaction();
                // App sometimes draws before the insets from WindowDecoration#relayout have
                // been added, so they must be added here
                mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext,
                        CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU);
                mWindowDecorByTaskId.get(mTaskId).addCaptionInset(wct);
                mDesktopTasksController.moveTaskToDesktop(mTaskId, wct,
                        DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON);
                decoration.closeHandleMenu();
            } else if (id == R.id.fullscreen_button) {
                decoration.closeHandleMenu();
                if (isTaskInSplitScreen(mTaskId)) {
                    mSplitScreenController.moveTaskToFullscreen(mTaskId,
                            SplitScreenController.EXIT_REASON_DESKTOP_MODE);
                } else {
                    mDesktopTasksController.moveToFullscreen(mTaskId,
                            DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON);
                }
            } else if (id == R.id.split_screen_button) {
                decoration.closeHandleMenu();
                // When the app enters split-select, the handle will no longer be visible, meaning
                // we shouldn't receive input for it any longer.
                decoration.disposeStatusBarInputLayer();
                mDesktopTasksController.requestSplit(decoration.mTaskInfo);
            } else if (id == R.id.open_in_browser_button) {
                // TODO(b/346441962): let the decoration handle the click gesture and only call back
                //  to the ViewModel via #setOpenInBrowserClickListener
                decoration.onOpenInBrowserClick();
            } else if (id == R.id.collapse_menu_button) {
                decoration.closeHandleMenu();
            } else if (id == R.id.new_window_button) {
                decoration.closeHandleMenu();
                mDesktopTasksController.openNewWindow(decoration.mTaskInfo);
            } else if (id == R.id.maximize_window) {
                // TODO(b/346441962): move click detection logic into the decor's
                //  {@link AppHeaderViewHolder}. Let it encapsulate the that and have it report
@@ -559,16 +581,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
        public boolean onTouch(View v, MotionEvent e) {
            final int id = v.getId();
            final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
            if (e.getActionMasked() == ACTION_OUTSIDE) {
                if (id == R.id.handle_menu) {
                    // Close handle menu on outside touch if menu is directly touchable; if not,
                    // it will be handled by handleEventOutsideCaption.
                    if (decoration.mTaskInfo.isFreeform()
                            || Flags.enableAdditionalWindowsAboveStatusBar()) {
                        decoration.closeHandleMenu();
                    }
                }
            }
            if ((e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN) {
                mTouchscreenInUse = e.getActionMasked() != ACTION_UP
                        && e.getActionMasked() != ACTION_CANCEL;
@@ -1191,14 +1203,36 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {

        final DesktopModeTouchEventListener touchEventListener =
                new DesktopModeTouchEventListener(taskInfo, dragPositioningCallback);
        windowDecoration.setOnMaximizeOrRestoreClickListener(this::onMaximizeOrRestore);
        windowDecoration.setOnLeftSnapClickListener((taskId, tag) -> {
            onSnapResize(taskId, true /* isLeft */);
        windowDecoration.setOnMaximizeOrRestoreClickListener(() -> {
            onMaximizeOrRestore(taskInfo.taskId, "maximize_menu");
            return Unit.INSTANCE;
        });
        windowDecoration.setOnLeftSnapClickListener(() -> {
            onSnapResize(taskInfo.taskId, true /* isLeft */);
            return Unit.INSTANCE;
        });
        windowDecoration.setOnRightSnapClickListener(() -> {
            onSnapResize(taskInfo.taskId, false /* isLeft */);
            return Unit.INSTANCE;
        });
        windowDecoration.setOnToDesktopClickListener(desktopModeTransitionSource -> {
            onToDesktop(taskInfo.taskId, desktopModeTransitionSource);
        });
        windowDecoration.setOnToFullscreenClickListener(() -> {
            onToFullscreen(taskInfo.taskId);
            return Unit.INSTANCE;
        });
        windowDecoration.setOnToSplitScreenClickListener(() -> {
            onToSplitScreen(taskInfo.taskId);
            return Unit.INSTANCE;
        });
        windowDecoration.setOpenInBrowserClickListener((uri) -> {
            onOpenInBrowser(taskInfo.taskId, uri);
        });
        windowDecoration.setOnRightSnapClickListener((taskId, tag) -> {
            onSnapResize(taskId, false /* isLeft */);
        windowDecoration.setOnNewWindowClickListener(() -> {
            onNewWindow(taskInfo.taskId);
            return Unit.INSTANCE;
        });
        windowDecoration.setOpenInBrowserClickListener(this::onOpenInBrowser);
        windowDecoration.setCaptionListeners(
                touchEventListener, touchEventListener, touchEventListener, touchEventListener);
        windowDecoration.setExclusionRegionListener(mExclusionRegionListener);
+61 −34
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;

import static com.android.launcher3.icons.BaseIconFactory.MODE_DEFAULT;
import static com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getFineResizeCornerSize;
import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getLargeResizeCornerSize;
@@ -77,18 +78,20 @@ import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.MultiInstanceHelper;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource;
import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.windowdecor.common.OnTaskActionClickListener;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
import com.android.wm.shell.windowdecor.viewholder.AppHandleViewHolder;
import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder;
import com.android.wm.shell.windowdecor.viewholder.WindowDecorationViewHolder;

import kotlin.Unit;
import kotlin.jvm.functions.Function0;

import java.util.function.Consumer;
import java.util.function.Supplier;

/**
@@ -115,9 +118,13 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
    private View.OnTouchListener mOnCaptionTouchListener;
    private View.OnLongClickListener mOnCaptionLongClickListener;
    private View.OnGenericMotionListener mOnCaptionGenericMotionListener;
    private OnTaskActionClickListener mOnMaximizeOrRestoreClickListener;
    private OnTaskActionClickListener mOnLeftSnapClickListener;
    private OnTaskActionClickListener mOnRightSnapClickListener;
    private Function0<Unit> mOnMaximizeOrRestoreClickListener;
    private Function0<Unit> mOnLeftSnapClickListener;
    private Function0<Unit> mOnRightSnapClickListener;
    private Consumer<DesktopModeTransitionSource> mOnToDesktopClickListener;
    private Function0<Unit> mOnToFullscreenClickListener;
    private Function0<Unit> mOnToSplitscreenClickListener;
    private Function0<Unit> mOnNewWindowClickListener;
    private DragPositioningCallback mDragPositioningCallback;
    private DragResizeInputListener mDragResizeListener;
    private DragDetector mDragDetector;
@@ -140,7 +147,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
    private CharSequence mAppName;
    private CapturedLink mCapturedLink;
    private Uri mGenericLink;
    private OpenInBrowserClickListener mOpenInBrowserClickListener;
    private Consumer<Uri> mOpenInBrowserClickListener;

    private ExclusionRegionListener mExclusionRegionListener;

@@ -228,22 +235,40 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
     * TODO(b/346441962): hook this up to double-tap and the header's maximize button, instead of
     *  having the ViewModel deal with parsing motion events.
     */
    void setOnMaximizeOrRestoreClickListener(OnTaskActionClickListener listener) {
    void setOnMaximizeOrRestoreClickListener(Function0<Unit> listener) {
        mOnMaximizeOrRestoreClickListener = listener;
    }

    /**
     * Register a listener to be called back when one of the tasks snap-left action is triggered.
     */
    void setOnLeftSnapClickListener(OnTaskActionClickListener listener) {
    /** Registers a listener to be called when the decoration's snap-left action is triggered.*/
    void setOnLeftSnapClickListener(Function0<Unit> listener) {
        mOnLeftSnapClickListener = listener;
    }

    /** Registers a listener to be called when the decoration's snap-right action is triggered. */
    void setOnRightSnapClickListener(Function0<Unit> listener) {
        mOnRightSnapClickListener = listener;
    }

    /** Registers a listener to be called when the decoration's to-desktop action is triggered. */
    void setOnToDesktopClickListener(Consumer<DesktopModeTransitionSource> listener) {
        mOnToDesktopClickListener = listener;
    }

    /**
     * Register a listener to be called back when one of the tasks' snap-right action is triggered.
     * Registers a listener to be called when the decoration's to-fullscreen action is triggered.
     */
    void setOnRightSnapClickListener(OnTaskActionClickListener listener) {
        mOnRightSnapClickListener = listener;
    void setOnToFullscreenClickListener(Function0<Unit> listener) {
        mOnToFullscreenClickListener = listener;
    }

    /** Registers a listener to be called when the decoration's to-split action is triggered. */
    void setOnToSplitScreenClickListener(Function0<Unit> listener) {
        mOnToSplitscreenClickListener = listener;
    }

    /** Registers a listener to be called when the decoration's new window action is triggered. */
    void setOnNewWindowClickListener(Function0<Unit> listener) {
        mOnNewWindowClickListener = listener;
    }

    void setCaptionListeners(
@@ -270,7 +295,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        mDragDetector.setTouchSlop(ViewConfiguration.get(mContext).getScaledTouchSlop());
    }

    void setOpenInBrowserClickListener(OpenInBrowserClickListener listener) {
    void setOpenInBrowserClickListener(Consumer<Uri> listener) {
        mOpenInBrowserClickListener = listener;
    }

@@ -445,14 +470,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        }
    }

    void onOpenInBrowserClick() {
        if (mOpenInBrowserClickListener == null || mHandleMenu == null) {
            return;
        }
        mOpenInBrowserClickListener.onClick(this, mHandleMenu.getOpenInBrowserLink());
        onCapturedLinkExpired();
    }

    @Nullable
    private Uri getBrowserLink() {
        // If the captured link is available and has not expired, return the captured link.
@@ -965,11 +982,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        mHandleMenu = mHandleMenuFactory.create(
                this,
                mRelayoutParams.mLayoutResId,
                mOnCaptionButtonClickListener,
                mOnCaptionTouchListener,
                mAppIconBitmap,
                mAppName,
                mDisplayController,
                splitScreenController,
                DesktopModeStatus.canEnterDesktopMode(mContext),
                Flags.enableDesktopWindowingMultiInstanceFeatures()
@@ -981,7 +995,28 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                mResult.mCaptionX
        );
        mWindowDecorViewHolder.onHandleMenuOpened();
        mHandleMenu.show();
        mHandleMenu.show(
                /* onToDesktopClickListener= */ () -> {
                    mOnToDesktopClickListener.accept(APP_HANDLE_MENU_BUTTON);
                    return Unit.INSTANCE;
                },
                /* onToFullscreenClickListener= */ mOnToFullscreenClickListener,
                /* onToSplitScreenClickListener= */ mOnToSplitscreenClickListener,
                /* onNewWindowClickListener= */ mOnNewWindowClickListener,
                /* openInBrowserClickListener= */ (uri) -> {
                    mOpenInBrowserClickListener.accept(uri);
                    onCapturedLinkExpired();
                    return Unit.INSTANCE;
                },
                /* onCloseMenuClickListener= */ () -> {
                    closeHandleMenu();
                    return Unit.INSTANCE;
                },
                /* onOutsideTouchListener= */ () -> {
                    closeHandleMenu();
                    return Unit.INSTANCE;
                }
        );
    }

    private void updateGenericLink() {
@@ -1320,14 +1355,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        }
    }


    /** Listener for the handle menu's "Open in browser" button */
    interface OpenInBrowserClickListener {

        /** Inform the implementing class that the "Open in browser" button has been clicked */
        void onClick(DesktopModeWindowDecoration decoration, Uri uri);
    }

    interface ExclusionRegionListener {
        /** Inform the implementing class of this task's change in region resize handles */
        void onExclusionRegionChanged(int taskId, Region region);
+288 −192

File changed.

Preview size limit exceeded, changes collapsed.

+10 −18
Original line number Diff line number Diff line
@@ -66,7 +66,6 @@ import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHo
import com.android.wm.shell.windowdecor.common.DecorThemeUtil
import com.android.wm.shell.windowdecor.common.OPACITY_12
import com.android.wm.shell.windowdecor.common.OPACITY_40
import com.android.wm.shell.windowdecor.common.OnTaskActionClickListener
import com.android.wm.shell.windowdecor.common.withAlpha
import java.util.function.Supplier

@@ -102,15 +101,15 @@ class MaximizeMenu(

    /** Creates and shows the maximize window. */
    fun show(
        onMaximizeClickListener: OnTaskActionClickListener,
        onLeftSnapClickListener: OnTaskActionClickListener,
        onRightSnapClickListener: OnTaskActionClickListener,
        onMaximizeOrRestoreClickListener: () -> Unit,
        onLeftSnapClickListener: () -> Unit,
        onRightSnapClickListener: () -> Unit,
        onHoverListener: (Boolean) -> Unit,
        onOutsideTouchListener: () -> Unit,
    ) {
        if (maximizeMenu != null) return
        createMaximizeMenu(
            onMaximizeClickListener = onMaximizeClickListener,
            onMaximizeClickListener = onMaximizeOrRestoreClickListener,
            onLeftSnapClickListener = onLeftSnapClickListener,
            onRightSnapClickListener = onRightSnapClickListener,
            onHoverListener = onHoverListener,
@@ -129,9 +128,9 @@ class MaximizeMenu(

    /** Create a maximize menu that is attached to the display area. */
    private fun createMaximizeMenu(
        onMaximizeClickListener: OnTaskActionClickListener,
        onLeftSnapClickListener: OnTaskActionClickListener,
        onRightSnapClickListener: OnTaskActionClickListener,
        onMaximizeClickListener: () -> Unit,
        onLeftSnapClickListener: () -> Unit,
        onRightSnapClickListener: () -> Unit,
        onHoverListener: (Boolean) -> Unit,
        onOutsideTouchListener: () -> Unit
    ) {
@@ -165,17 +164,10 @@ class MaximizeMenu(
            menuHeight = menuHeight,
            menuPadding = menuPadding,
        ).also { menuView ->
            val taskId = taskInfo.taskId
            menuView.bind(taskInfo)
            menuView.onMaximizeClickListener = {
                onMaximizeClickListener.onClick(taskId, "maximize_menu_option")
            }
            menuView.onLeftSnapClickListener = {
                onLeftSnapClickListener.onClick(taskId, "left_snap_option")
            }
            menuView.onRightSnapClickListener = {
                onRightSnapClickListener.onClick(taskId, "right_snap_option")
            }
            menuView.onMaximizeClickListener = onMaximizeClickListener
            menuView.onLeftSnapClickListener = onLeftSnapClickListener
            menuView.onRightSnapClickListener = onRightSnapClickListener
            menuView.onMenuHoverListener = onHoverListener
            menuView.onOutsideTouchListener = onOutsideTouchListener
            viewHost.setView(menuView.rootView, lp)
+23 −6
Original line number Diff line number Diff line
@@ -613,7 +613,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
     * Create a window associated with this WindowDecoration.
     * Note that subclass must dispose of this when the task is hidden/closed.
     *
     * @param layoutId     layout to make the window from
     * @param v            View to attach to the window
     * @param t            the transaction to apply
     * @param xPos         x position of new window
     * @param yPos         y position of new window
@@ -621,9 +621,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
     * @param height       height of new window
     * @return the {@link AdditionalViewHostViewContainer} that was added.
     */
    AdditionalViewHostViewContainer addWindow(int layoutId, String namePrefix,
            SurfaceControl.Transaction t, SurfaceSyncGroup ssg, int xPos, int yPos,
            int width, int height) {
    AdditionalViewHostViewContainer addWindow(@NonNull View v, @NonNull String namePrefix,
            @NonNull SurfaceControl.Transaction t, @NonNull SurfaceSyncGroup ssg,
            int xPos, int yPos, int width, int height) {
        final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
        SurfaceControl windowSurfaceControl = builder
                .setName(namePrefix + " of Task=" + mTaskInfo.taskId)
@@ -631,8 +631,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
                .setParent(mDecorationContainerSurface)
                .setCallsite("WindowDecoration.addWindow")
                .build();
        View v = LayoutInflater.from(mDecorWindowContext).inflate(layoutId, null);

        t.setPosition(windowSurfaceControl, xPos, yPos)
                .setWindowCrop(windowSurfaceControl, width, height)
                .show(windowSurfaceControl);
@@ -652,6 +650,25 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
                mSurfaceControlTransactionSupplier);
    }

    /**
     * Create a window associated with this WindowDecoration.
     * Note that subclass must dispose of this when the task is hidden/closed.
     *
     * @param layoutId     layout to make the window from
     * @param t            the transaction to apply
     * @param xPos         x position of new window
     * @param yPos         y position of new window
     * @param width        width of new window
     * @param height       height of new window
     * @return the {@link AdditionalViewHostViewContainer} that was added.
     */
    AdditionalViewHostViewContainer addWindow(int layoutId, String namePrefix,
            SurfaceControl.Transaction t, SurfaceSyncGroup ssg, int xPos, int yPos,
            int width, int height) {
        final View v = LayoutInflater.from(mDecorWindowContext).inflate(layoutId, null);
        return addWindow(v, namePrefix, t, ssg, xPos, yPos, width, height);
    }

    /**
     * Adds caption inset source to a WCT
     */
Loading