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

Commit c94ba127 authored by Omar Elmekkawy's avatar Omar Elmekkawy
Browse files

[7/n] Adding infrastructure to break tiling on certain events

This CL adds functionality to break tiling in the following scenarios:
* Drag resizing use edge or corner resizing
* Minimize or maximize tasks
* onTaskVanishing
* onTaskRelaunch outside desktop mode
* on window decor drag
* on entering overview or swiping to home

Flag: com.android.window.flags.enable_tile_resizing
Test: tests are WIP
Bug: 369546904

Change-Id: Ie06fa28a0701edfb052a546a2ac8f0941f5d2fcf
parent 0b3877a7
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -677,7 +677,8 @@ public abstract class WMShellModule {
            Transitions transitions,
            ShellTaskOrganizer shellTaskOrganizer,
            ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler,
            ReturnToDragStartAnimator returnToDragStartAnimator) {
            ReturnToDragStartAnimator returnToDragStartAnimator,
            @DynamicOverride DesktopRepository desktopRepository) {
        return new DesktopTilingDecorViewModel(
                context,
                displayController,
@@ -686,7 +687,8 @@ public abstract class WMShellModule {
                transitions,
                shellTaskOrganizer,
                toggleResizeDesktopTaskTransitionHandler,
                returnToDragStartAnimator
                returnToDragStartAnimator,
                desktopRepository
        );
    }

+13 −2
Original line number Diff line number Diff line
@@ -240,6 +240,7 @@ class DesktopTasksController(
                override fun onAnimationStateChanged(running: Boolean) {
                    logV("Recents animation state changed running=%b", running)
                    recentsAnimationRunning = running
                    desktopTilingDecorViewModel.onOverviewAnimationStateChange(running)
                }
            }
        )
@@ -495,6 +496,7 @@ class DesktopTasksController(
        taskInfo: RunningTaskInfo,
    ): ((IBinder) -> Unit)? {
        val taskId = taskInfo.taskId
        desktopTilingDecorViewModel.removeTaskIfTiled(displayId, taskId)
        if (taskRepository.isOnlyVisibleNonClosingTask(taskId)) {
            removeWallpaperActivity(wct)
        }
@@ -535,6 +537,7 @@ class DesktopTasksController(
    /** Move a task with given `taskId` to fullscreen */
    fun moveToFullscreen(taskId: Int, transitionSource: DesktopModeTransitionSource) {
        shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { task ->
            desktopTilingDecorViewModel.removeTaskIfTiled(task.displayId, taskId)
            moveToFullscreenWithAnimation(task, task.positionInParent, transitionSource)
        }
    }
@@ -542,6 +545,7 @@ class DesktopTasksController(
    /** Enter fullscreen by moving the focused freeform task in given `displayId` to fullscreen. */
    fun enterFullscreen(displayId: Int, transitionSource: DesktopModeTransitionSource) {
        getFocusedFreeformTask(displayId)?.let {
            desktopTilingDecorViewModel.removeTaskIfTiled(displayId, it.taskId)
            moveToFullscreenWithAnimation(it, it.positionInParent, transitionSource)
        }
    }
@@ -549,6 +553,7 @@ class DesktopTasksController(
    /** Move a desktop app to split screen. */
    fun moveToSplit(task: RunningTaskInfo) {
        logV( "moveToSplit taskId=%s", task.taskId)
        desktopTilingDecorViewModel.removeTaskIfTiled(task.displayId, task.taskId)
        val wct = WindowContainerTransaction()
        wct.setBounds(task.token, Rect())
        // Rather than set windowing mode to multi-window at task level, set it to
@@ -806,13 +811,13 @@ class DesktopTasksController(
        } else {
            // Save current bounds so that task can be restored back to original bounds if necessary
            // and toggle to the stable bounds.
            desktopTilingDecorViewModel.removeTaskIfTiled(taskInfo.displayId, taskInfo.taskId)
            taskRepository.saveBoundsBeforeMaximize(taskInfo.taskId, currentTaskBounds)

            destinationBounds.set(calculateMaximizeBounds(displayLayout, taskInfo))
        }



        val shouldRestoreToSnap =
            isMaximized && isTaskSnappedToHalfScreen(taskInfo, destinationBounds)

@@ -1517,7 +1522,11 @@ class DesktopTasksController(
            addPendingMinimizeTransition(transition, taskToMinimize)
            return wct
        }
        return if (wct.isEmpty) null else wct
        if (!wct.isEmpty) {
            desktopTilingDecorViewModel.removeTaskIfTiled(task.displayId, task.taskId)
            return wct
        }
        return null
    }

    private fun handleFullscreenTaskLaunch(
@@ -1584,6 +1593,7 @@ class DesktopTasksController(

        if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()) {
            taskRepository.addClosingTask(task.displayId, task.taskId)
            desktopTilingDecorViewModel.removeTaskIfTiled(task.displayId, task.taskId)
        }

        taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
@@ -1831,6 +1841,7 @@ class DesktopTasksController(
        taskBounds: Rect
    ) {
        if (taskInfo.windowingMode != WINDOWING_MODE_FREEFORM) return
        desktopTilingDecorViewModel.removeTaskIfTiled(taskInfo.displayId, taskInfo.taskId)
        updateVisualIndicator(taskInfo, taskSurface, inputX, taskBounds.top.toFloat(),
            DragStartState.FROM_FREEFORM)
    }
+4 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.desktopmode.DesktopRepository
import com.android.wm.shell.desktopmode.DesktopTasksController
import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator
import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler
@@ -43,6 +44,7 @@ class DesktopTilingDecorViewModel(
    private val shellTaskOrganizer: ShellTaskOrganizer,
    private val toggleResizeDesktopTaskTransitionHandler: ToggleResizeDesktopTaskTransitionHandler,
    private val returnToDragStartAnimator: ReturnToDragStartAnimator,
    private val taskRepository: DesktopRepository,
) {
    @VisibleForTesting
    var tilingTransitionHandlerByDisplayId = SparseArray<DesktopTilingWindowDecoration>()
@@ -68,10 +70,12 @@ class DesktopTilingDecorViewModel(
                            shellTaskOrganizer,
                            toggleResizeDesktopTaskTransitionHandler,
                            returnToDragStartAnimator,
                            taskRepository,
                        )
                    tilingTransitionHandlerByDisplayId.put(displayId, newHandler)
                    newHandler
                }
        transitions.registerObserver(handler)
        return handler.onAppTiled(
            taskInfo,
            desktopModeWindowDecoration,
+113 −4
Original line number Diff line number Diff line
@@ -27,7 +27,9 @@ import android.util.Slog
import android.view.SurfaceControl
import android.view.SurfaceControl.Transaction
import android.view.WindowManager.TRANSIT_CHANGE
import android.view.WindowManager.TRANSIT_TO_BACK
import android.view.WindowManager.TRANSIT_TO_FRONT
import android.window.TransitionInfo
import android.window.TransitionRequestInfo
import android.window.WindowContainerTransaction
import com.android.launcher3.icons.BaseIconFactory
@@ -39,15 +41,19 @@ import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.desktopmode.DesktopRepository
import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition
import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator
import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.transition.Transitions.TRANSIT_MINIMIZE
import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration
import com.android.wm.shell.windowdecor.DragPositioningCallbackUtility
import com.android.wm.shell.windowdecor.DragPositioningCallbackUtility.DragEventListener
import com.android.wm.shell.windowdecor.DragResizeWindowGeometry
import com.android.wm.shell.windowdecor.DragResizeWindowGeometry.DisabledEdge.NONE
import com.android.wm.shell.windowdecor.ResizeVeil
import com.android.wm.shell.windowdecor.extension.isFullscreen
import java.util.function.Supplier

class DesktopTilingWindowDecoration(
@@ -60,12 +66,14 @@ class DesktopTilingWindowDecoration(
    private val shellTaskOrganizer: ShellTaskOrganizer,
    private val toggleResizeDesktopTaskTransitionHandler: ToggleResizeDesktopTaskTransitionHandler,
    private val returnToDragStartAnimator: ReturnToDragStartAnimator,
    private val taskRepository: DesktopRepository,
    private val transactionSupplier: Supplier<Transaction> = Supplier { Transaction() },
) :
    Transitions.TransitionHandler,
    ShellTaskOrganizer.FocusListener,
    ShellTaskOrganizer.TaskVanishedListener,
    DragEventListener {
    DragEventListener,
    Transitions.TransitionObserver {
    companion object {
        private val TAG: String = DesktopTilingWindowDecoration::class.java.simpleName
        private const val TILING_DIVIDER_TAG = "Tiling Divider"
@@ -161,10 +169,16 @@ class DesktopTilingWindowDecoration(
            rightTaskResizingHelper?.initIfNeeded()
            leftTaskResizingHelper
                ?.desktopModeWindowDecoration
                ?.updateDisabledResizingEdge(DragResizeWindowGeometry.DisabledEdge.RIGHT)
                ?.updateDisabledResizingEdge(
                    DragResizeWindowGeometry.DisabledEdge.RIGHT,
                    /* shouldDelayUpdate = */ false,
                )
            rightTaskResizingHelper
                ?.desktopModeWindowDecoration
                ?.updateDisabledResizingEdge(DragResizeWindowGeometry.DisabledEdge.LEFT)
                ?.updateDisabledResizingEdge(
                    DragResizeWindowGeometry.DisabledEdge.LEFT,
                    /* shouldDelayUpdate = */ false,
                )
        } else if (firstTiledApp) {
            shellTaskOrganizer.addTaskVanishedListener(this)
        }
@@ -303,6 +317,32 @@ class DesktopTilingWindowDecoration(
        return null
    }

    override fun onDragStart(taskId: Int) {}

    override fun onDragMove(taskId: Int) {
        removeTaskIfTiled(taskId)
    }

    override fun onTransitionReady(
        transition: IBinder,
        info: TransitionInfo,
        startTransaction: Transaction,
        finishTransaction: Transaction,
    ) {
        for (change in info.changes) {
            change.taskInfo?.let {
                if (it.isFullscreen || isMinimized(change.mode, info.type)) {
                    removeTaskIfTiled(it.taskId, /* taskVanished= */ false, it.isFullscreen)
                }
            }
        }
    }

    private fun isMinimized(changeMode: Int, infoType: Int): Boolean {
        return (changeMode == TRANSIT_TO_BACK &&
            (infoType == TRANSIT_MINIMIZE || infoType == TRANSIT_TO_BACK))
    }

    class AppResizingHelper(
        val taskInfo: RunningTaskInfo,
        val desktopModeWindowDecoration: DesktopModeWindowDecoration,
@@ -384,6 +424,12 @@ class DesktopTilingWindowDecoration(
            taskInfo.taskId != rightTaskResizingHelper?.taskInfo?.taskId
    }

    override fun onFocusTaskChanged(taskInfo: RunningTaskInfo?) {
        if (taskInfo != null) {
            moveTiledPairToFront(taskInfo)
        }
    }

    private fun isTilingRefocused(taskInfo: RunningTaskInfo): Boolean {
        return !isTilingFocused &&
            taskInfo.isFocused &&
@@ -405,6 +451,62 @@ class DesktopTilingWindowDecoration(
        return wct
    }

    fun removeTaskIfTiled(
        taskId: Int,
        taskVanished: Boolean = false,
        shouldDelayUpdate: Boolean = false,
    ) {
        if (taskId == leftTaskResizingHelper?.taskInfo?.taskId) {
            removeTask(leftTaskResizingHelper, taskVanished, shouldDelayUpdate)
            leftTaskResizingHelper = null
            rightTaskResizingHelper
                ?.desktopModeWindowDecoration
                ?.updateDisabledResizingEdge(NONE, shouldDelayUpdate)
            tearDownTiling()
            return
        }

        if (taskId == rightTaskResizingHelper?.taskInfo?.taskId) {
            removeTask(rightTaskResizingHelper, taskVanished, shouldDelayUpdate)
            rightTaskResizingHelper = null
            leftTaskResizingHelper
                ?.desktopModeWindowDecoration
                ?.updateDisabledResizingEdge(NONE, shouldDelayUpdate)
            tearDownTiling()
        }
    }

    private fun removeTask(
        appResizingHelper: AppResizingHelper?,
        taskVanished: Boolean = false,
        shouldDelayUpdate: Boolean,
    ) {
        if (appResizingHelper == null) return
        if (!taskVanished) {
            appResizingHelper.desktopModeWindowDecoration.removeDragResizeListener(this)
            appResizingHelper.desktopModeWindowDecoration.updateDisabledResizingEdge(
                NONE,
                shouldDelayUpdate,
            )
        }
        appResizingHelper.dispose()
    }

    fun onOverviewAnimationStateChange(isRunning: Boolean) {
        if (!isTilingManagerInitialised) return

        if (isRunning) {
            desktopTilingDividerWindowManager?.hideDividerBar()
        } else if (allTiledTasksVisible()) {
            desktopTilingDividerWindowManager?.showDividerBar()
        }
    }

    override fun onTaskVanished(taskInfo: RunningTaskInfo?) {
        val taskId = taskInfo?.taskId ?: return
        removeTaskIfTiled(taskId, taskVanished = true, shouldDelayUpdate = true)
    }

    fun moveTiledPairToFront(taskInfo: RunningTaskInfo): Boolean {
        if (!isTilingManagerInitialised) return false

@@ -416,7 +518,7 @@ class DesktopTilingWindowDecoration(

        val leftTiledTask = leftTaskResizingHelper ?: return false
        val rightTiledTask = rightTaskResizingHelper ?: return false

        if (!allTiledTasksVisible()) return false
        val isLeftOnTop = taskInfo.taskId == leftTiledTask.taskInfo.taskId
        if (isTilingRefocused(taskInfo)) {
            val t = transactionSupplier.get()
@@ -444,6 +546,13 @@ class DesktopTilingWindowDecoration(
        return false
    }

    private fun allTiledTasksVisible(): Boolean {
        val leftTiledTask = leftTaskResizingHelper ?: return false
        val rightTiledTask = rightTaskResizingHelper ?: return false
        return taskRepository.isVisibleTask(leftTiledTask.taskInfo.taskId) &&
            taskRepository.isVisibleTask(rightTiledTask.taskInfo.taskId)
    }

    private fun isResizeWithinSizeConstraints(
        newLeftBounds: Rect,
        newRightBounds: Rect,
+4 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.desktopmode.DesktopRepository
import com.android.wm.shell.desktopmode.DesktopTasksController
import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator
@@ -48,6 +49,7 @@ class DesktopTilingDecorViewModelTest : ShellTestCase() {
    private val syncQueueMock: SyncTransactionQueue = mock()
    private val transitionsMock: Transitions = mock()
    private val shellTaskOrganizerMock: ShellTaskOrganizer = mock()
    private val desktopRepository: DesktopRepository = mock()
    private val toggleResizeDesktopTaskTransitionHandlerMock:
        ToggleResizeDesktopTaskTransitionHandler =
        mock()
@@ -69,6 +71,7 @@ class DesktopTilingDecorViewModelTest : ShellTestCase() {
                shellTaskOrganizerMock,
                toggleResizeDesktopTaskTransitionHandlerMock,
                returnToDragStartAnimatorMock,
                desktopRepository,
            )
    }

@@ -108,7 +111,7 @@ class DesktopTilingDecorViewModelTest : ShellTestCase() {
        )
        desktopTilingDecorViewModel.removeTaskIfTiled(task1.displayId, task1.taskId)

        verify(desktopTilingDecoration, times(1)).removeTaskIfTiled(any(), any())
        verify(desktopTilingDecoration, times(1)).removeTaskIfTiled(any(), any(), any())
    }

    @Test
Loading