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

Commit 70398e94 authored by Omar Elmekkawy's avatar Omar Elmekkawy
Browse files

Add multi user support for tiling.

This CL changes the behavior of switching users from completely tearing
down tiling, to just hiding the divider, while adding a new dimension
in tiling handlers to accommodate data for parallel tiling sessions.

Flag: com.android.window.flags.enable_tile_resizing
Test: unit tests and on device testing
Bug: 382445971
Change-Id: I3fc434a89d362b9f3a2739e5629a630cfe04793d
parent 421044be
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -896,7 +896,8 @@ public abstract class WMShellModule {
            WindowDecorTaskResourceLoader windowDecorTaskResourceLoader,
            FocusTransitionObserver focusTransitionObserver,
            @ShellMainThread ShellExecutor mainExecutor,
            DesktopState desktopState) {
            DesktopState desktopState,
            ShellInit shellInit) {
        return new DesktopTilingDecorViewModel(
                context,
                mainDispatcher,
@@ -913,7 +914,8 @@ public abstract class WMShellModule {
                windowDecorTaskResourceLoader,
                focusTransitionObserver,
                mainExecutor,
                desktopState
                desktopState,
                shellInit
        );
    }

+1 −1
Original line number Diff line number Diff line
@@ -3887,7 +3887,7 @@ class DesktopTasksController(
        userId = newUserId
        taskRepository = userRepositories.getProfile(userId)
        if (this::snapEventHandler.isInitialized) {
            snapEventHandler.onUserChange()
            snapEventHandler.onUserChange(userId)
        }
    }

+2 −2
Original line number Diff line number Diff line
@@ -959,8 +959,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
    }

    @Override
    public void onUserChange() {
        mDesktopTilingDecorViewModel.onUserChange();
    public void onUserChange(int userId) {
        mDesktopTilingDecorViewModel.onUserChange(userId);
    }

    @Override
+40 −19
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.graphics.Rect
import android.util.SparseArray
import android.window.DisplayAreaInfo
import android.window.WindowContainerTransaction
import androidx.core.util.getOrElse
import androidx.core.util.valueIterator
import com.android.internal.annotations.VisibleForTesting
import com.android.wm.shell.R
@@ -41,6 +42,7 @@ import com.android.wm.shell.recents.RecentsTransitionStateListener
import com.android.wm.shell.shared.annotations.ShellBackgroundThread
import com.android.wm.shell.shared.annotations.ShellMainThread
import com.android.wm.shell.shared.desktopmode.DesktopState
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.FocusTransitionObserver
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration
@@ -66,14 +68,16 @@ class DesktopTilingDecorViewModel(
    private val focusTransitionObserver: FocusTransitionObserver,
    private val mainExecutor: ShellExecutor,
    private val desktopState: DesktopState,
    private val shellInit: ShellInit,
) : DisplayChangeController.OnDisplayChangingListener {
    @VisibleForTesting
    var tilingTransitionHandlerByDisplayId = SparseArray<DesktopTilingWindowDecoration>()
    var tilingHandlerByUserAndDisplayId = SparseArray<SparseArray<DesktopTilingWindowDecoration>>()
    var currentUserId: Int = -1

    init {
        // TODO(b/374309287): Move this interface implementation to
        // [DesktopModeWindowDecorViewModel] when the migration is done.
        displayController.addDisplayChangingController(this)
        shellInit.addInitCallback({ displayController.addDisplayChangingController(this) }, this)
    }

    fun snapToHalfScreen(
@@ -84,9 +88,14 @@ class DesktopTilingDecorViewModel(
    ): Boolean {
        val displayId = taskInfo.displayId
        val handler =
            tilingTransitionHandlerByDisplayId.get(displayId)
                ?: run {
                    val newHandler =
            tilingHandlerByUserAndDisplayId
                .getOrElse(currentUserId) {
                    SparseArray<DesktopTilingWindowDecoration>().also {
                        tilingHandlerByUserAndDisplayId[currentUserId] = it
                    }
                }
                .getOrElse(displayId) {
                    val userHandlerList = tilingHandlerByUserAndDisplayId[currentUserId]
                    DesktopTilingWindowDecoration(
                            context,
                            mainDispatcher,
@@ -106,8 +115,7 @@ class DesktopTilingDecorViewModel(
                            mainExecutor,
                            desktopState,
                        )
                    tilingTransitionHandlerByDisplayId.put(displayId, newHandler)
                    newHandler
                        .also { userHandlerList[displayId] = it }
                }
        transitions.registerObserver(handler)
        return handler.onAppTiled(
@@ -119,32 +127,41 @@ class DesktopTilingDecorViewModel(
    }

    fun removeTaskIfTiled(displayId: Int, taskId: Int) {
        tilingTransitionHandlerByDisplayId.get(displayId)?.removeTaskIfTiled(taskId)
        tilingHandlerByUserAndDisplayId[currentUserId]?.get(displayId)?.removeTaskIfTiled(taskId)
    }

    fun moveTaskToFrontIfTiled(taskInfo: RunningTaskInfo): Boolean {
        // Always pass focus=true because taskInfo.isFocused is not updated yet.
        return tilingTransitionHandlerByDisplayId
            .get(taskInfo.displayId)
        return tilingHandlerByUserAndDisplayId[currentUserId]
            ?.get(taskInfo.displayId)
            ?.moveTiledPairToFront(taskInfo.taskId, isFocusedOnDisplay = true) ?: false
    }

    fun onOverviewAnimationStateChange(
        @RecentsTransitionStateListener.RecentsTransitionState state: Int
    ) {
        for (tilingHandler in tilingTransitionHandlerByDisplayId.valueIterator()) {
        val activeUserHandlers = tilingHandlerByUserAndDisplayId[currentUserId] ?: return
        for (tilingHandler in activeUserHandlers.valueIterator()) {
            tilingHandler.onOverviewAnimationStateChange(state)
        }
    }

    fun onUserChange() {
        for (tilingHandler in tilingTransitionHandlerByDisplayId.valueIterator()) {
            tilingHandler.resetTilingSession()
    fun onUserChange(userId: Int) {
        if (userId == currentUserId) return
        try {
            val activeUserHandlers = tilingHandlerByUserAndDisplayId[currentUserId] ?: return
            for (tilingHandler in activeUserHandlers.valueIterator()) {
                tilingHandler.hideDividerBar()
            }
        } finally {
            currentUserId = userId
        }
    }

    fun onTaskInfoChange(taskInfo: RunningTaskInfo) {
        tilingTransitionHandlerByDisplayId.get(taskInfo.displayId)?.onTaskInfoChange(taskInfo)
        tilingHandlerByUserAndDisplayId[currentUserId]
            ?.get(taskInfo.displayId)
            ?.onTaskInfoChange(taskInfo)
    }

    override fun onDisplayChange(
@@ -157,12 +174,14 @@ class DesktopTilingDecorViewModel(
        // Exit if the rotation hasn't changed or is changed by 180 degrees. [fromRotation] and
        // [toRotation] can be one of the [@Surface.Rotation] values.
        if ((fromRotation % 2 == toRotation % 2)) return
        tilingTransitionHandlerByDisplayId.get(displayId)?.resetTilingSession()
        tilingHandlerByUserAndDisplayId[currentUserId]?.get(displayId)?.resetTilingSession()
    }

    fun getRightSnapBoundsIfTiled(displayId: Int): Rect {
        val tilingBounds =
            tilingTransitionHandlerByDisplayId.get(displayId)?.getRightSnapBoundsIfTiled()
            tilingHandlerByUserAndDisplayId[currentUserId]
                ?.get(displayId)
                ?.getRightSnapBoundsIfTiled()
        if (tilingBounds != null) {
            return tilingBounds
        }
@@ -183,7 +202,9 @@ class DesktopTilingDecorViewModel(

    fun getLeftSnapBoundsIfTiled(displayId: Int): Rect {
        val tilingBounds =
            tilingTransitionHandlerByDisplayId.get(displayId)?.getLeftSnapBoundsIfTiled()
            tilingHandlerByUserAndDisplayId[currentUserId]
                ?.get(displayId)
                ?.getLeftSnapBoundsIfTiled()
        if (tilingBounds != null) {
            return tilingBounds
        }
+6 −3
Original line number Diff line number Diff line
@@ -445,7 +445,7 @@ class DesktopTilingWindowDecoration(
                    removeTaskIfTiled(it.taskId, /* taskVanished= */ false, it.isFullscreen)
                } else if (isEnteringPip(change, info.type)) {
                    removeTaskIfTiled(it.taskId, /* taskVanished= */ true, it.isFullscreen)
                } else if (isTransitionToFront(change.mode, info.type)) {
                } else if (isTransitionToFront(change.mode)) {
                    handleTaskBroughtToFront(it.taskId)
                    leftTaskBroughtToFront =
                        leftTaskBroughtToFront ||
@@ -496,8 +496,8 @@ class DesktopTilingWindowDecoration(
        return false
    }

    private fun isTransitionToFront(changeMode: Int, transitionType: Int): Boolean =
        changeMode == TRANSIT_TO_FRONT && transitionType == TRANSIT_TO_FRONT
    private fun isTransitionToFront(changeMode: Int): Boolean =
        changeMode == TRANSIT_TO_FRONT

    class AppResizingHelper(
        val taskInfo: RunningTaskInfo,
@@ -707,6 +707,9 @@ class DesktopTilingWindowDecoration(
        removeTaskIfTiled(taskId, taskVanished = true, shouldDelayUpdate = true)
    }

    fun hideDividerBar() {
        desktopTilingDividerWindowManager?.hideDividerBar()
    }
    /**
     * Moves the tiled pair to the front of the task stack, if the [taskInfo] is focused and one of
     * the two tiled tasks.
Loading