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

Commit 05cd0081 authored by Maryam Dehaini's avatar Maryam Dehaini
Browse files

[8/N] WindowDecor refactor: Move WindowDecor#addWindow to HandleMenu

Handle menu is the only one that uses WindowDecor#addWindow, so this
change moves the method to better encapsulate menu logic.

Bug: 409648813
Flag: com.android.window.flags.enable_window_decoration_refactor
Test: m
Change-Id: I588610fa61e23a254d9523ed75e5c3df6be5a9fc
parent 1a53ff91
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -193,7 +193,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
    private final AppHandleViewHolder.Factory mAppHandleViewHolderFactory;
    private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
    private final MaximizeMenuFactory mMaximizeMenuFactory;
    private final HandleMenuFactory mHandleMenuFactory;
    private final HandleMenu.HandleMenuFactory mHandleMenuFactory;
    private final AppToWebGenericLinksParser mGenericLinksParser;
    private final AssistContentRequester mAssistContentRequester;
    private final DesktopModeCompatPolicy mDesktopModeCompatPolicy;
@@ -268,7 +268,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                new SurfaceControlViewHostFactory() {},
                windowDecorViewHostSupplier,
                DefaultMaximizeMenuFactory.INSTANCE,
                DefaultHandleMenuFactory.INSTANCE, multiInstanceHelper,
                HandleMenu.HandleMenuFactory.INSTANCE, multiInstanceHelper,
                windowDecorCaptionRepository, desktopModeEventLogger,
                desktopModeUiEventLogger, desktopModeCompatPolicy,
                desktopState, desktopConfig, windowDecorationActions);
@@ -305,7 +305,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
            SurfaceControlViewHostFactory surfaceControlViewHostFactory,
            @NonNull WindowDecorViewHostSupplier<WindowDecorViewHost> windowDecorViewHostSupplier,
            MaximizeMenuFactory maximizeMenuFactory,
            HandleMenuFactory handleMenuFactory,
            HandleMenu.HandleMenuFactory handleMenuFactory,
            MultiInstanceHelper multiInstanceHelper,
            WindowDecorCaptionRepository windowDecorCaptionRepository,
            DesktopModeEventLogger desktopModeEventLogger,
+187 −71
Original line number Diff line number Diff line
@@ -25,10 +25,12 @@ import android.content.Intent
import android.content.res.ColorStateList
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.PixelFormat
import android.graphics.Point
import android.graphics.PointF
import android.graphics.Rect
import android.os.Bundle
import android.view.Display
import android.view.Display.DEFAULT_DISPLAY
import android.view.LayoutInflater
import android.view.MotionEvent
@@ -38,11 +40,13 @@ import android.view.View
import android.view.View.OnClickListener
import android.view.ViewGroup
import android.view.WindowInsets.Type.systemBars
import android.view.WindowManager
import android.view.WindowManager.LayoutParams
import android.view.WindowlessWindowManager
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.Space
import android.window.DesktopExperienceFlags
import android.window.DesktopModeFlags
import android.window.SurfaceSyncGroup
import androidx.annotation.StringRes
@@ -64,8 +68,10 @@ import com.android.wm.shell.shared.bubbles.ContextUtils.isRtl
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON
import com.android.wm.shell.shared.split.SplitScreenConstants
import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.windowdecor.WindowDecoration2.SurfaceControlViewHostFactory
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer
import com.android.wm.shell.windowdecor.common.DecorThemeUtil
import com.android.wm.shell.windowdecor.common.DrawableInsets
import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader
@@ -77,7 +83,6 @@ import com.android.wm.shell.windowdecor.extension.isPinned
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.MainCoroutineDispatcher
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -91,10 +96,14 @@ import kotlinx.coroutines.withContext
 * Windowing Options(Proto 2 only): Buttons to change windowing modes.
 * Additional Options: Miscellaneous functions including screenshot and closing task.
 */
class HandleMenu(
class HandleMenu private constructor(
    @ShellMainThread private val mainDispatcher: CoroutineDispatcher,
    @ShellBackgroundThread private val bgScope: CoroutineScope,
    private val parentDecor: DesktopModeWindowDecoration,
    private val context: Context,
    private val taskInfo: RunningTaskInfo,
    private val parentSurface: SurfaceControl,
    private val display: Display,
    private val parentDecor: DesktopModeWindowDecoration?,
    private val windowManagerWrapper: WindowManagerWrapper,
    private val windowDecorationActions: WindowDecorationActions,
    private val taskResourceLoader: WindowDecorTaskResourceLoader,
@@ -112,11 +121,11 @@ class HandleMenu(
    private val captionWidth: Int,
    private val captionHeight: Int,
    captionX: Int,
    captionY: Int
    captionY: Int,
    private val surfaceControlBuilderSupplier: () -> SurfaceControl.Builder,
    private val surfaceControlTransactionSupplier: () -> SurfaceControl.Transaction,
    private val surfaceControlViewHostFactory: SurfaceControlViewHostFactory,
) {
    private val context: Context = parentDecor.mDecorWindowContext
    private val taskInfo: RunningTaskInfo = parentDecor.mTaskInfo

    private val isViewAboveStatusBar: Boolean
        get() = (DesktopModeFlags.ENABLE_HANDLE_INPUT_FIX.isTrue() && !taskInfo.isFreeform)

@@ -237,6 +246,7 @@ class HandleMenu(
        }
        val x = handleMenuPosition.x.toInt()
        val y = handleMenuPosition.y.toInt()
        val lpFlags = LayoutParams.FLAG_NOT_FOCUSABLE or LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
        handleMenuViewContainer =
            if ((!taskInfo.isFreeform && DesktopModeFlags.ENABLE_HANDLE_INPUT_FIX.isTrue())
                || forceShowSystemBars
@@ -248,8 +258,7 @@ class HandleMenu(
                    y = y,
                    width = menuWidth,
                    height = menuHeight,
                    flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
                            WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                    flags = lpFlags,
                    view = handleMenuView.rootView,
                    forciblyShownTypes = if (forceShowSystemBars) {
                        systemBars()
@@ -259,8 +268,13 @@ class HandleMenu(
                    ignoreCutouts = Flags.showAppHandleLargeScreens()
                            || BubbleAnythingFlagHelper.enableBubbleToFullscreen()
                )
            } else if (DesktopExperienceFlags.ENABLE_WINDOW_DECORATION_REFACTOR.isTrue) {
                createAdditionalViewHostViewContainer(
                    handleMenuView.rootView, t, x, y, menuWidth, menuHeight, lpFlags
                )
            } else {
                parentDecor.addWindow(
                val decor = checkNotNull(parentDecor) { "Expected non-null parent decoration" }
                decor.addWindow(
                    handleMenuView.rootView, "Handle Menu", t, ssg, x, y, menuWidth, menuHeight
                )
            }
@@ -268,6 +282,55 @@ class HandleMenu(
        this.handleMenuView = handleMenuView
    }

    /** Creates and returns an [AdditionalViewHostViewContainer] for the handle menu. */
    private fun createAdditionalViewHostViewContainer(
        v: View,
        t: SurfaceControl.Transaction,
        xPos: Int,
        yPos: Int,
        width: Int,
        height: Int,
        flags: Int,
    ): AdditionalViewHostViewContainer {
        val builder = surfaceControlBuilderSupplier()
        val windowSurfaceControl = builder
            .setName("Handle menu of Task=" + taskInfo.taskId)
            .setContainerLayer()
            .setParent(parentSurface)
            .setCallsite("HandleMenu.createAdditionalViewHostViewContainer")
            .build()
        t.setPosition(windowSurfaceControl, xPos.toFloat(), yPos.toFloat())
            .setWindowCrop(windowSurfaceControl, width, height)
            .show(windowSurfaceControl)
        val lp = LayoutParams(
            width,
            height,
            LayoutParams.TYPE_APPLICATION,
            flags,
            PixelFormat.TRANSPARENT
        ).apply {
            title = "Handle menu of task=" + taskInfo.taskId
            setTrustedOverlay()
        }
        val windowManager = WindowlessWindowManager(
            taskInfo.configuration,
            windowSurfaceControl,
            /* hostInputTransferToken= */ null
        )
        val viewHost = surfaceControlViewHostFactory.create(
            context,
            display,
            windowManager
        ).apply {
            setView(v, lp)
        }
        return AdditionalViewHostViewContainer(
            windowSurfaceControl,
            viewHost,
            surfaceControlTransactionSupplier,
        )
    }

    /**
     * Updates handle menu's position variables to reflect its next position.
     */
@@ -429,7 +492,8 @@ class HandleMenu(
        }
        if (!shouldShowRestartButton) {
            menuHeight -= loadDimensionPixelSize(
                R.dimen.desktop_mode_handle_menu_restart_button_height)
                R.dimen.desktop_mode_handle_menu_restart_button_height
            )
        }
        if (!shouldShowMoreActionsPill) {
            menuHeight -= pillTopMargin
@@ -753,7 +817,7 @@ class HandleMenu(
            appIconView.setImageBitmap(icon)
        }

        /** Animates the menu openInAppOrBrowserg. */
        /** Animates the menu opening. */
        fun animateOpenMenu() {
            if (taskInfo.isFullscreen || taskInfo.isMultiWindow) {
                animator.animateCaptionHandleExpandToOpen()
@@ -929,7 +993,8 @@ class HandleMenu(
                            topRadius, topRadius, topRadius, topRadius,
                            bottomRadius, bottomRadius, bottomRadius, bottomRadius
                        ),
                        drawableInsets = DrawableInsets())
                        drawableInsets = DrawableInsets()
                    )
                }
            }
            // The restart button is nested to show an error icon on the right. Update the
@@ -956,7 +1021,8 @@ class HandleMenu(
                background = createBackgroundDrawable(
                    color = style.textColor,
                    cornerRadius = handleMenuCornerRadius,
                    drawableInsets = DrawableInsets())
                    drawableInsets = DrawableInsets()
                )
                textView.apply {
                    text = btnText
                    setTextColor(style.textColor)
@@ -971,7 +1037,8 @@ class HandleMenu(
                background = createBackgroundDrawable(
                    color = style.textColor,
                    cornerRadius = iconButtonRippleRadius,
                    drawableInsets = iconButtonDrawableInsetEnd)
                    drawableInsets = iconButtonDrawableInsetEnd
                )
            }
        }

@@ -1003,14 +1070,17 @@ class HandleMenu(
        fun shouldShowRestartButton(taskInfo: RunningTaskInfo): Boolean =
            taskInfo.appCompatTaskInfo.isRestartMenuEnabledForDisplayMove
    }
}

/** A factory interface to create a [HandleMenu]. */
interface HandleMenuFactory {
    /** Factory to create a new [HandleMenu].  */
    object HandleMenuFactory {
        @JvmOverloads
        fun create(
        @ShellMainThread mainDispatcher: MainCoroutineDispatcher,
            @ShellMainThread mainDispatcher: CoroutineDispatcher,
            @ShellBackgroundThread bgScope: CoroutineScope,
        parentDecor: DesktopModeWindowDecoration,
            context: Context,
            taskInfo: RunningTaskInfo,
            parentSurface: SurfaceControl,
            display: Display,
            windowManagerWrapper: WindowManagerWrapper,
            windowDecorationActions: WindowDecorationActions,
            taskResourceLoader: WindowDecorTaskResourceLoader,
@@ -1029,13 +1099,47 @@ interface HandleMenuFactory {
            captionHeight: Int,
            captionX: Int,
            captionY: Int,
    ): HandleMenu
}
            surfaceControlBuilderSupplier: () -> SurfaceControl.Builder =
                { SurfaceControl.Builder() },
            surfaceControlTransactionSupplier: () -> SurfaceControl.Transaction =
                { SurfaceControl.Transaction() },
            surfaceControlViewHostFactory: SurfaceControlViewHostFactory =
                object : SurfaceControlViewHostFactory {},
        ): HandleMenu = HandleMenu(
            mainDispatcher,
            bgScope,
            context,
            taskInfo,
            parentSurface,
            display,
            parentDecor = null,
            windowManagerWrapper,
            windowDecorationActions,
            taskResourceLoader,
            layoutResId,
            splitScreenController,
            shouldShowWindowingPill,
            shouldShowNewWindowButton,
            shouldShowManageWindowsButton,
            shouldShowChangeAspectRatioButton,
            shouldShowDesktopModeButton,
            shouldShowRestartButton,
            isBrowserApp,
            openInAppOrBrowserIntent,
            desktopModeUiEventLogger,
            captionWidth,
            captionHeight,
            captionX,
            captionY,
            surfaceControlBuilderSupplier,
            surfaceControlTransactionSupplier,
            surfaceControlViewHostFactory,
        )

/** A [HandleMenuFactory] implementation that creates a [HandleMenu].  */
object DefaultHandleMenuFactory : HandleMenuFactory {
    override fun create(
        @ShellMainThread mainDispatcher: MainCoroutineDispatcher,
        @Deprecated("Handle menu should no longer have reference to window decoration")
        @JvmOverloads
        fun create(
            @ShellMainThread mainDispatcher: CoroutineDispatcher,
            @ShellBackgroundThread bgScope: CoroutineScope,
            parentDecor: DesktopModeWindowDecoration,
            windowManagerWrapper: WindowManagerWrapper,
@@ -1056,10 +1160,19 @@ object DefaultHandleMenuFactory : HandleMenuFactory {
            captionHeight: Int,
            captionX: Int,
            captionY: Int,
    ): HandleMenu {
        return HandleMenu(
            surfaceControlBuilderSupplier: () -> SurfaceControl.Builder =
                { SurfaceControl.Builder() },
            surfaceControlTransactionSupplier: () -> SurfaceControl.Transaction =
                { SurfaceControl.Transaction() },
            surfaceControlViewHostFactory: SurfaceControlViewHostFactory =
                object : SurfaceControlViewHostFactory {}
        ): HandleMenu = HandleMenu(
            mainDispatcher,
            bgScope,
            parentDecor.mDecorWindowContext,
            parentDecor.mTaskInfo,
            parentDecor.mDecorationContainerSurface,
            parentDecor.mDisplay,
            parentDecor,
            windowManagerWrapper,
            windowDecorationActions,
@@ -1079,6 +1192,9 @@ object DefaultHandleMenuFactory : HandleMenuFactory {
            captionHeight,
            captionX,
            captionY,
            surfaceControlBuilderSupplier,
            surfaceControlTransactionSupplier,
            surfaceControlViewHostFactory,
        )
    }
}
+0 −69
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.Color
import android.graphics.PixelFormat
import android.graphics.Rect
import android.graphics.Region
import android.gui.BorderSettings
@@ -40,14 +39,11 @@ import android.window.DesktopExperienceFlags
import android.window.TaskConstants
import android.window.WindowContainerTransaction
import com.android.app.tracing.traceSection
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.common.BoxShadowHelper
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayController.OnDisplaysChangedListener
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_WINDOW_DECORATION
import com.android.wm.shell.shared.annotations.ShellMainThread
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer
import com.android.wm.shell.windowdecor.caption.CaptionController
import com.android.wm.shell.windowdecor.extension.getDimensionPixelSize
import com.android.wm.shell.windowdecor.extension.isVisible
@@ -469,71 +465,6 @@ abstract class WindowDecoration2<T>(
        surfaceControlSupplier: () -> SurfaceControl
    ) = surfaceControlSupplier().apply { copyFrom(sc, TAG) }

    /**
     * Create a window associated with this WindowDecoration.
     * Note that subclass must dispose of this when the task is hidden/closed.
     *
     * @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
     * @param width        width of new window
     * @param height       height of new window
     * @return the [AdditionalViewHostViewContainer] that was added.
     */
    fun addWindow(
        v: View,
        namePrefix: String,
        t: SurfaceControl.Transaction,
        xPos: Int,
        yPos: Int,
        width: Int,
        height: Int
    ): AdditionalViewHostViewContainer? {
        if (display == null) {
            ProtoLog.e(WM_SHELL_WINDOW_DECORATION, "Attempting to add window to null display")
            return null
        }
        val builder = surfaceControlBuilderSupplier()
        val windowSurfaceControl = builder
            .setName(namePrefix + " of Task=" + taskInfo.taskId)
            .setContainerLayer()
            .setParent(checkNotNull(decorationContainerSurface) {
                "expected non-null decoration container surface control"
            })
            .setCallsite("WindowDecoration2.addWindow")
            .build()
        t.setPosition(windowSurfaceControl, xPos.toFloat(), yPos.toFloat())
            .setWindowCrop(windowSurfaceControl, width, height)
            .show(windowSurfaceControl)
        val lp = LayoutParams(
            width,
            height,
            LayoutParams.TYPE_APPLICATION,
            LayoutParams.FLAG_NOT_FOCUSABLE or LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
            PixelFormat.TRANSPARENT
        ).apply {
            title = "Additional window of Task=" + taskInfo.taskId
            setTrustedOverlay()
        }
        val windowManager = WindowlessWindowManager(
            taskInfo.configuration,
            windowSurfaceControl, /* hostInputTransferToken = */ null
        )
        val viewHost = surfaceControlViewHostFactory.create(
            decorWindowContext,
            checkNotNull(display) { "expected non-null display" },
            windowManager
        ).apply {
            setView(v, lp)
        }
        return AdditionalViewHostViewContainer(
            windowSurfaceControl,
            viewHost,
            surfaceControlTransactionSupplier,
        )
    }

    /**  Holds the data required to update the window decorations. */
    data class RelayoutParams(
        val runningTaskInfo: RunningTaskInfo,
+1 −1
Original line number Diff line number Diff line
@@ -243,7 +243,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase {
    @Mock
    private HandleMenu mMockHandleMenu;
    @Mock
    private HandleMenuFactory mMockHandleMenuFactory;
    private HandleMenu.HandleMenuFactory mMockHandleMenuFactory;
    @Mock
    private MultiInstanceHelper mMockMultiInstanceHelper;
    @Mock
+67 −23
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.view.SurfaceControlViewHost
import android.view.View
import android.view.WindowInsets.Type.systemBars
import android.view.WindowManager
import android.window.DesktopExperienceFlags
import androidx.core.graphics.toPointF
import androidx.test.filters.SmallTest
import com.android.window.flags.Flags
@@ -48,6 +49,7 @@ import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOT
import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED
import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.windowdecor.WindowDecoration2.SurfaceControlViewHostFactory
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer
import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader
@@ -87,6 +89,10 @@ class HandleMenuTest : ShellTestCase() {
    @Mock
    private lateinit var displayController: DisplayController
    @Mock
    private lateinit var mockDisplay: Display
    @Mock
    private lateinit var mockSurfaceControl: SurfaceControl
    @Mock
    private lateinit var splitScreenController: SplitScreenController
    @Mock
    private lateinit var displayLayout: DisplayLayout
@@ -100,7 +106,10 @@ class HandleMenuTest : ShellTestCase() {
    private lateinit var mockAppIcon: Bitmap
    @Mock
    private lateinit var mockDesktopModeUiEventLogger: DesktopModeUiEventLogger
    @Mock
    private lateinit var mockSurfaceControlViewHostFactory: SurfaceControlViewHostFactory

    private val handleMenuFactory = HandleMenu.HandleMenuFactory
    private lateinit var handleMenu: HandleMenu

    @Before
@@ -119,11 +128,15 @@ class HandleMenuTest : ShellTestCase() {
        whenever(mockDesktopWindowDecoration.addWindow(
            any<View>(), any(), any(), any(), anyInt(), anyInt(), anyInt(), anyInt())
        ).thenReturn(mockAdditionalViewHostViewContainer)
        mockDesktopWindowDecoration.mDecorationContainerSurface = mockSurfaceControl
        mockDesktopWindowDecoration.mDisplay = mockDisplay
        whenever(mockAdditionalViewHostViewContainer.view).thenReturn(menuView)
        whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout)
        whenever(displayLayout.width()).thenReturn(DISPLAY_BOUNDS.width())
        whenever(displayLayout.height()).thenReturn(DISPLAY_BOUNDS.height())
        whenever(displayLayout.isLandscape).thenReturn(true)
        whenever(mockSurfaceControlViewHostFactory.create(any(), any(), any(), any()))
            .thenReturn(mockSurfaceControlViewHost)
        mContext.orCreateTestableResources.apply {
            addOverride(R.dimen.desktop_mode_handle_menu_width, MENU_WIDTH)
            addOverride(R.dimen.desktop_mode_handle_menu_height, MENU_HEIGHT)
@@ -279,7 +292,36 @@ class HandleMenuTest : ShellTestCase() {
            }
            else -> error("Invalid windowing mode")
        }
        val handleMenu = HandleMenu(
        val handleMenu = if (DesktopExperienceFlags.ENABLE_WINDOW_DECORATION_REFACTOR.isTrue) {
            handleMenuFactory.create(
                StandardTestDispatcher(testScheduler),
                this,
                mContext,
                mockDesktopWindowDecoration.mTaskInfo,
                mockSurfaceControl,
                mockDisplay,
                WindowManagerWrapper(mockWindowManager),
                mockWindowDecorationActions,
                mockTaskResourceLoader,
                layoutId,
                splitScreenController,
                shouldShowWindowingPill = true,
                shouldShowNewWindowButton = true,
                shouldShowManageWindowsButton = false,
                shouldShowChangeAspectRatioButton = false,
                shouldShowDesktopModeButton = true,
                shouldShowRestartButton = true,
                isBrowserApp = false,
                openInAppOrBrowserIntent = null,
                mockDesktopModeUiEventLogger,
                captionWidth = HANDLE_WIDTH,
                captionHeight = 50,
                captionX = captionX,
                captionY = 0,
                surfaceControlViewHostFactory = mockSurfaceControlViewHostFactory
            )
        } else {
            handleMenuFactory.create(
                StandardTestDispatcher(testScheduler),
                this,
                mockDesktopWindowDecoration,
@@ -295,13 +337,15 @@ class HandleMenuTest : ShellTestCase() {
                shouldShowDesktopModeButton = true,
                shouldShowRestartButton = true,
                isBrowserApp = false,
            null /* openInAppOrBrowserIntent */,
                openInAppOrBrowserIntent = null,
                mockDesktopModeUiEventLogger,
                captionWidth = HANDLE_WIDTH,
                captionHeight = 50,
                captionX = captionX,
                captionY = 0,
                surfaceControlViewHostFactory = mockSurfaceControlViewHostFactory
            )
        }
        handleMenu.show(
            openInAppOrBrowserClickListener = mock(),
            onOpenByDefaultClickListener = mock(),