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

Commit 23a67d4a authored by Jorge Gil's avatar Jorge Gil
Browse files

Force show system bars while menus are open in desktop immersive

Keeps the bars showing while the Handle Menu or Manage Windows menus are
open, and adjusts their position on screen to account for App Header
padding.

This requires changing these windows to use
AdditionalSystemViewContainer because setting forciblyShownTypes on
windowless windows has no effect on the system bars' visibility.

Flag: com.android.window.flags.enable_fully_immersive_in_desktop
Bug: 372319957
Test: enter desktop immersive with YT on Chrome, check menus force-show
the system bars and they're anchored to the App Chip instead of the top
of the screen/task.

Change-Id: I2cfd7b416c66ed89d2e2556d644c01bcab846dcd
parent 707aca0d
Loading
Loading
Loading
Loading
+8 −8
Original line number Diff line number Diff line
@@ -95,15 +95,15 @@ class DesktopHandleManageWindowsMenu(
    override fun addToContainer(menuView: ManageWindowsView) {
        val menuPosition = calculateMenuPosition()
        menuViewContainer = AdditionalSystemViewContainer(
            windowManagerWrapper,
            callerTaskInfo.taskId,
            menuPosition.x,
            menuPosition.y,
            menuView.menuWidth,
            menuView.menuHeight,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
            windowManagerWrapper = windowManagerWrapper,
            taskId = callerTaskInfo.taskId,
            x = menuPosition.x,
            y = menuPosition.y,
            width = menuView.menuWidth,
            height = menuView.menuHeight,
            flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
                    WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
            menuView.rootView
            view = menuView.rootView,
        )
    }
}
+48 −10
Original line number Diff line number Diff line
@@ -22,14 +22,19 @@ import android.graphics.PixelFormat
import android.graphics.Point
import android.view.SurfaceControl
import android.view.SurfaceControlViewHost
import android.view.WindowInsets.Type.systemBars
import android.view.WindowManager
import android.view.WindowlessWindowManager
import android.window.TaskConstants
import android.window.TaskSnapshot
import androidx.compose.ui.graphics.toArgb
import com.android.internal.annotations.VisibleForTesting
import com.android.window.flags.Flags
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.desktopmode.DesktopRepository
import com.android.wm.shell.shared.desktopmode.ManageWindowsViewContainer
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
@@ -41,9 +46,12 @@ import java.util.function.Supplier
 */
class DesktopHeaderManageWindowsMenu(
    private val callerTaskInfo: RunningTaskInfo,
    private val x: Int,
    private val y: Int,
    private val displayController: DisplayController,
    private val rootTdaOrganizer: RootTaskDisplayAreaOrganizer,
    context: Context,
    private val desktopRepository: DesktopRepository,
    private val surfaceControlBuilderSupplier: Supplier<SurfaceControl.Builder>,
    private val surfaceControlTransactionSupplier: Supplier<SurfaceControl.Transaction>,
    snapshotList: List<Pair<Int, TaskSnapshot>>,
@@ -53,7 +61,8 @@ class DesktopHeaderManageWindowsMenu(
    context,
    DecorThemeUtil(context).getColorScheme(callerTaskInfo).background.toArgb()
) {
    private var menuViewContainer: AdditionalViewContainer? = null
    @VisibleForTesting
    var menuViewContainer: AdditionalViewContainer? = null

    init {
        show(snapshotList, onIconClickListener, onOutsideClickListener)
@@ -64,8 +73,37 @@ class DesktopHeaderManageWindowsMenu(
    }

    override fun addToContainer(menuView: ManageWindowsView) {
        val taskBounds = callerTaskInfo.getConfiguration().windowConfiguration.bounds
        val menuPosition = Point(taskBounds.left, taskBounds.top)
        val menuPosition = Point(x, y)
        val flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
                WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH or
                WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
        menuViewContainer = if (Flags.enableFullyImmersiveInDesktop()
            && desktopRepository.isTaskInFullImmersiveState(callerTaskInfo.taskId)) {
            // Use system view container so that forcibly shown system bars take effect in
            // immersive.
            createAsSystemViewContainer(menuPosition, flags)
        } else {
            createAsViewHostContainer(menuPosition, flags)
        }
    }

    private fun createAsSystemViewContainer(position: Point, flags: Int): AdditionalViewContainer {
        return AdditionalSystemViewContainer(
            windowManagerWrapper = WindowManagerWrapper(
                context.getSystemService(WindowManager::class.java)
            ),
            taskId = callerTaskInfo.taskId,
            x = position.x,
            y = position.y,
            width = menuView.menuWidth,
            height = menuView.menuHeight,
            flags = flags,
            forciblyShownTypes = systemBars(),
            view = menuView.rootView
        )
    }

    private fun createAsViewHostContainer(position: Point, flags: Int): AdditionalViewContainer {
        val builder = surfaceControlBuilderSupplier.get()
        rootTdaOrganizer.attachToDisplayArea(callerTaskInfo.displayId, builder)
        val leash = builder
@@ -73,11 +111,10 @@ class DesktopHeaderManageWindowsMenu(
            .setContainerLayer()
            .build()
        val lp = WindowManager.LayoutParams(
            menuView.menuWidth, menuView.menuHeight,
            menuView.menuWidth,
            menuView.menuHeight,
            WindowManager.LayoutParams.TYPE_APPLICATION,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                    or WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
            flags,
            PixelFormat.TRANSPARENT
        )
        val windowManager = WindowlessWindowManager(
@@ -93,11 +130,12 @@ class DesktopHeaderManageWindowsMenu(
        menuView.let { viewHost.setView(it.rootView, lp) }
        val t = surfaceControlTransactionSupplier.get()
        t.setLayer(leash, TaskConstants.TASK_CHILD_LAYER_FLOATING_MENU)
            .setPosition(leash, menuPosition.x.toFloat(), menuPosition.y.toFloat())
            .setPosition(leash, position.x.toFloat(), position.y.toFloat())
            .show(leash)
        t.apply()
        menuViewContainer = AdditionalViewHostViewContainer(
            leash, viewHost,
        return AdditionalViewHostViewContainer(
            leash,
            viewHost,
            surfaceControlTransactionSupplier
        )
    }
+19 −3
Original line number Diff line number Diff line
@@ -454,7 +454,13 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        }

        if (isHandleMenuActive()) {
            mHandleMenu.relayout(startT, mResult.mCaptionX);
            mHandleMenu.relayout(
                    startT,
                    mResult.mCaptionX,
                    // Add top padding to the caption Y so that the menu is shown over what is the
                    // actual contents of the caption, ignoring padding. This is currently relevant
                    // to the Header in desktop immersive.
                    mResult.mCaptionY + mResult.mCaptionTopPadding);
        }

        if (isOpenByDefaultDialogActive()) {
@@ -1258,6 +1264,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                && Flags.enableDesktopWindowingMultiInstanceFeatures();
        final boolean shouldShowManageWindowsButton = supportsMultiInstance
                && mMinimumInstancesFound;
        final boolean inDesktopImmersive = mDesktopRepository
                .isTaskInFullImmersiveState(mTaskInfo.taskId);
        mHandleMenu = mHandleMenuFactory.create(
                this,
                mWindowManagerWrapper,
@@ -1271,7 +1279,11 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                getBrowserLink(),
                mResult.mCaptionWidth,
                mResult.mCaptionHeight,
                mResult.mCaptionX
                mResult.mCaptionX,
                // Add top padding to the caption Y so that the menu is shown over what is the
                // actual contents of the caption, ignoring padding. This is currently relevant
                // to the Header in desktop immersive.
                mResult.mCaptionY + mResult.mCaptionTopPadding
        );
        mWindowDecorViewHolder.onHandleMenuOpened();
        mHandleMenu.show(
@@ -1302,7 +1314,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                /* onOutsideTouchListener= */ () -> {
                    closeHandleMenu();
                    return Unit.INSTANCE;
                }
                },
                /* forceShowSystemBars= */ inDesktopImmersive
        );
        if (canEnterDesktopMode(mContext) && Flags.enableDesktopWindowingAppHandleEducation()) {
            notifyCaptionStateChanged();
@@ -1316,9 +1329,12 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        if (mTaskInfo.isFreeform()) {
            mManageWindowsMenu = new DesktopHeaderManageWindowsMenu(
                    mTaskInfo,
                    /* x= */ mResult.mCaptionX,
                    /* y= */ mResult.mCaptionY + mResult.mCaptionTopPadding,
                    mDisplayController,
                    mRootTaskDisplayAreaOrganizer,
                    mContext,
                    mDesktopRepository,
                    mSurfaceControlBuilderSupplier,
                    mSurfaceControlTransactionSupplier,
                    snapshotList,
+29 −19
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.view.MotionEvent
import android.view.MotionEvent.ACTION_OUTSIDE
import android.view.SurfaceControl
import android.view.View
import android.view.WindowInsets.Type.systemBars
import android.view.WindowManager
import android.widget.Button
import android.widget.ImageButton
@@ -73,7 +74,8 @@ class HandleMenu(
    private val openInBrowserIntent: Intent?,
    private val captionWidth: Int,
    private val captionHeight: Int,
    captionX: Int
    captionX: Int,
    captionY: Int
) {
    private val context: Context = parentDecor.mDecorWindowContext
    private val taskInfo: RunningTaskInfo = parentDecor.mTaskInfo
@@ -110,7 +112,7 @@ class HandleMenu(
        get() = openInBrowserIntent != null

    init {
        updateHandleMenuPillPositions(captionX)
        updateHandleMenuPillPositions(captionX, captionY)
    }

    fun show(
@@ -123,6 +125,7 @@ class HandleMenu(
        onOpenByDefaultClickListener: () -> Unit,
        onCloseMenuClickListener: () -> Unit,
        onOutsideTouchListener: () -> Unit,
        forceShowSystemBars: Boolean = false,
    ) {
        val ssg = SurfaceSyncGroup(TAG)
        val t = SurfaceControl.Transaction()
@@ -139,6 +142,7 @@ class HandleMenu(
            onOpenByDefaultClickListener = onOpenByDefaultClickListener,
            onCloseMenuClickListener = onCloseMenuClickListener,
            onOutsideTouchListener = onOutsideTouchListener,
            forceShowSystemBars = forceShowSystemBars,
        )
        ssg.addTransaction(t)
        ssg.markSyncReady()
@@ -157,7 +161,8 @@ class HandleMenu(
        openInBrowserClickListener: (Intent) -> Unit,
        onOpenByDefaultClickListener: () -> Unit,
        onCloseMenuClickListener: () -> Unit,
        onOutsideTouchListener: () -> Unit
        onOutsideTouchListener: () -> Unit,
        forceShowSystemBars: Boolean = false,
    ) {
        val handleMenuView = HandleMenuView(
            context = context,
@@ -185,7 +190,7 @@ class HandleMenu(
        val x = handleMenuPosition.x.toInt()
        val y = handleMenuPosition.y.toInt()
        handleMenuViewContainer =
            if (!taskInfo.isFreeform && Flags.enableHandleInputFix()) {
            if ((!taskInfo.isFreeform && Flags.enableHandleInputFix()) || forceShowSystemBars) {
                AdditionalSystemViewContainer(
                    windowManagerWrapper = windowManagerWrapper,
                    taskId = taskInfo.taskId,
@@ -196,7 +201,8 @@ class HandleMenu(
                    flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
                            WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH or
                            WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                    view = handleMenuView.rootView
                    view = handleMenuView.rootView,
                    forciblyShownTypes = if (forceShowSystemBars) { systemBars() } else { 0 }
                )
            } else {
                parentDecor.addWindow(
@@ -210,15 +216,15 @@ class HandleMenu(
    /**
     * Updates handle menu's position variables to reflect its next position.
     */
    private fun updateHandleMenuPillPositions(captionX: Int) {
    private fun updateHandleMenuPillPositions(captionX: Int, captionY: Int) {
        val menuX: Int
        val menuY: Int
        val taskBounds = taskInfo.getConfiguration().windowConfiguration.bounds
        updateGlobalMenuPosition(taskBounds, captionX)
        updateGlobalMenuPosition(taskBounds, captionX, captionY)
        if (layoutResId == R.layout.desktop_mode_app_header) {
            // Align the handle menu to the left side of the caption.
            menuX = marginMenuStart
            menuY = marginMenuTop
            menuY = captionY + marginMenuTop
        } else {
            if (Flags.enableHandleInputFix()) {
                // In a focused decor, we use global coordinates for handle menu. Therefore we
@@ -228,26 +234,26 @@ class HandleMenu(
                menuY = globalMenuPosition.y
            } else {
                menuX = (taskBounds.width() / 2) - (menuWidth / 2)
                menuY = marginMenuTop
                menuY = captionY + marginMenuTop
            }
        }
        // Handle Menu position setup.
        handleMenuPosition.set(menuX.toFloat(), menuY.toFloat())
    }

    private fun updateGlobalMenuPosition(taskBounds: Rect, captionX: Int) {
    private fun updateGlobalMenuPosition(taskBounds: Rect, captionX: Int, captionY: Int) {
        val nonFreeformX = captionX + (captionWidth / 2) - (menuWidth / 2)
        when {
            taskInfo.isFreeform -> {
                globalMenuPosition.set(
                    /* x = */ taskBounds.left + marginMenuStart,
                    /* y = */ taskBounds.top + marginMenuTop
                    /* y = */ taskBounds.top + captionY + marginMenuTop
                )
            }
            taskInfo.isFullscreen -> {
                globalMenuPosition.set(
                    /* x = */ nonFreeformX,
                    /* y = */ marginMenuTop
                    /* y = */ marginMenuTop + captionY
                )
            }
            taskInfo.isMultiWindow -> {
@@ -261,13 +267,13 @@ class HandleMenu(
                    SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT -> {
                        globalMenuPosition.set(
                            /* x = */ leftOrTopStageBounds.width() + nonFreeformX,
                            /* y = */ marginMenuTop
                            /* y = */ captionY + marginMenuTop
                        )
                    }
                    SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT -> {
                        globalMenuPosition.set(
                            /* x = */ nonFreeformX,
                            /* y = */ marginMenuTop
                            /* y = */ captionY + marginMenuTop
                        )
                    }
                }
@@ -280,10 +286,11 @@ class HandleMenu(
     */
    fun relayout(
        t: SurfaceControl.Transaction,
        captionX: Int
        captionX: Int,
        captionY: Int,
    ) {
        handleMenuViewContainer?.let { container ->
            updateHandleMenuPillPositions(captionX)
            updateHandleMenuPillPositions(captionX, captionY)
            container.setPosition(t, handleMenuPosition.x, handleMenuPosition.y)
        }
    }
@@ -675,7 +682,8 @@ interface HandleMenuFactory {
        openInBrowserIntent: Intent?,
        captionWidth: Int,
        captionHeight: Int,
        captionX: Int
        captionX: Int,
        captionY: Int,
    ): HandleMenu
}

@@ -694,7 +702,8 @@ object DefaultHandleMenuFactory : HandleMenuFactory {
        openInBrowserIntent: Intent?,
        captionWidth: Int,
        captionHeight: Int,
        captionX: Int
        captionX: Int,
        captionY: Int,
    ): HandleMenu {
        return HandleMenu(
            parentDecor,
@@ -709,7 +718,8 @@ object DefaultHandleMenuFactory : HandleMenuFactory {
            openInBrowserIntent,
            captionWidth,
            captionHeight,
            captionX
            captionX,
            captionY,
        )
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -256,6 +256,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
        outResult.mCaptionWidth = params.mCaptionWidthId != Resources.ID_NULL
                ? loadDimensionPixelSize(resources, params.mCaptionWidthId) : taskBounds.width();
        outResult.mCaptionX = (outResult.mWidth - outResult.mCaptionWidth) / 2;
        outResult.mCaptionY = 0;
        outResult.mCaptionTopPadding = params.mCaptionTopPadding;

        updateDecorationContainerSurface(startT, outResult);
        updateCaptionContainerSurface(startT, outResult);
@@ -786,6 +788,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
        int mCaptionHeight;
        int mCaptionWidth;
        int mCaptionX;
        int mCaptionY;
        int mCaptionTopPadding;
        final Region mCustomizableCaptionRegion = Region.obtain();
        int mWidth;
        int mHeight;
@@ -797,6 +801,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
            mCaptionHeight = 0;
            mCaptionWidth = 0;
            mCaptionX = 0;
            mCaptionY = 0;
            mCaptionTopPadding = 0;
            mCustomizableCaptionRegion.setEmpty();
            mRootView = null;
        }
Loading