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

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

Add support to tiling display disconnect.

This CL adds support to display disconnect for tiling for both when
freeform tasks are projected from a small form device, and for display
extension on the likes of tablets.

Flag: com.android.window.flags.enable_tile_resizing
Flag: com.android.window.flags.enable_display_disconnect_interaction
Test: unit tests and on device testing
Bug: 413020665
Change-Id: I356136c612eadc536fa45ec0467ae76fd11786c8
parent e2727ce3
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -658,11 +658,14 @@ class DesktopTasksController(
        val wct = WindowContainerTransaction()
        // TODO: b/391652399 - Investigate why sometimes disconnect results in a black background.
        //  Additionally, investigate why wallpaper goes to front for inactive users.
        val desktopModeSupportedOnDisplay =
            desktopState.isDesktopModeSupportedOnDisplay(destinationDisplayId)
        snapEventHandler.onDisplayDisconnected(disconnectedDisplayId, desktopModeSupportedOnDisplay)
        removeWallpaperTask(wct, disconnectedDisplayId)
        removeHomeTask(wct, disconnectedDisplayId)
        userRepositories.forAllRepositories { desktopRepository ->
            val deskIds = desktopRepository.getDeskIds(disconnectedDisplayId).toList()
            if (desktopState.isDesktopModeSupportedOnDisplay(destinationDisplayId)) {
            if (desktopModeSupportedOnDisplay) {
                // Desktop supported on display; reparent desks, focused desk on top.
                for (deskId in deskIds) {
                    val toTop =
@@ -3634,12 +3637,14 @@ class DesktopTasksController(
                        displayId = displayId,
                        deskId = deskId,
                        enterTaskId = newTaskIdInFront,
                        runOnTransitEnd = { snapEventHandler.onDeskActivated(deskId, displayId) },
                    )
                } else {
                    DeskTransition.ActivateDesk(
                        token = transition,
                        displayId = displayId,
                        deskId = deskId,
                        runOnTransitEnd = { snapEventHandler.onDeskActivated(deskId, displayId) },
                    )
                }
            desksTransitionObserver.addPendingTransition(activateDeskTransition)
+31 −6
Original line number Diff line number Diff line
@@ -39,6 +39,17 @@ sealed interface DeskTransition {
    /** A transition to activate a desk in its display. */
    data class ActivateDesk(override val token: IBinder, val displayId: Int, val deskId: Int) :
        DeskTransition {
        constructor(
            token: IBinder,
            displayId: Int,
            deskId: Int,
            runOnTransitEnd: (() -> Unit)?,
        ) : this(token, displayId, deskId) {
            this.runOnTransitEnd = runOnTransitEnd
        }

        var runOnTransitEnd: (() -> Unit)? = null

        override fun copyWithToken(token: IBinder): DeskTransition = copy(token)
    }

@@ -49,19 +60,33 @@ sealed interface DeskTransition {
        val deskId: Int,
        val enterTaskId: Int,
    ) : DeskTransition {
        constructor(
            token: IBinder,
            displayId: Int,
            deskId: Int,
            enterTaskId: Int,
            runOnTransitEnd: (() -> Unit)?,
        ) : this(token, displayId, deskId, enterTaskId) {
            this.runOnTransitEnd = runOnTransitEnd
        }

        var runOnTransitEnd: (() -> Unit)? = null

        override fun copyWithToken(token: IBinder): DeskTransition = copy(token)
    }

    /** A transition to deactivate a desk. */
    data class DeactivateDesk(
        override val token: IBinder,
        val deskId: Int,
    ) : DeskTransition {
        constructor(token: IBinder, deskId: Int, runOnTransitEnd: (() -> Unit)?)
                : this(token, deskId) {
    data class DeactivateDesk(override val token: IBinder, val deskId: Int) : DeskTransition {
        constructor(
            token: IBinder,
            deskId: Int,
            runOnTransitEnd: (() -> Unit)?,
        ) : this(token, deskId) {
            this.runOnTransitEnd = runOnTransitEnd
        }

        var runOnTransitEnd: (() -> Unit)? = null

        override fun copyWithToken(token: IBinder): DeskTransition = copy(token)
    }

+2 −0
Original line number Diff line number Diff line
@@ -120,6 +120,7 @@ class DesksTransitionObserver(
                    displayId = deskTransition.displayId,
                    deskId = deskTransition.deskId,
                )
                deskTransition.runOnTransitEnd?.invoke()
            }
            is DeskTransition.ActivateDeskWithTask -> {
                val deskId = deskTransition.deskId
@@ -157,6 +158,7 @@ class DesksTransitionObserver(
                } else {
                    logW("ActivateDeskWithTask: did not find task change")
                }
                deskTransition.runOnTransitEnd?.invoke()
            }
            is DeskTransition.DeactivateDesk -> handleDeactivateDeskTransition(info, deskTransition)
            is DeskTransition.ChangeDeskDisplay -> handleChangeDeskDisplay(info, deskTransition)
+31 −0
Original line number Diff line number Diff line
@@ -970,6 +970,30 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
                currentDragBounds);
    }

    @Override
    public void onDeskActivated(int deskId, int displayId) {
        if (!mDesktopTilingDecorViewModel.onDeskActivated(deskId)) {
            return;
        }

        final DesktopRepository repository = mDesktopUserRepositories.getCurrent();
        final Integer leftTaskId = repository.getLeftTiledTask(deskId);
        final Integer rightTaskId =  repository.getRightTiledTask(deskId);
        if (leftTaskId != null) {
            final DesktopModeWindowDecoration decor = mWindowDecorByTaskId.get(leftTaskId);
            final RunningTaskInfo taskInfo = decor.mTaskInfo;
            final Rect currentBounds = taskInfo.configuration.windowConfiguration.getBounds();
            snapPersistedTaskToHalfScreen(taskInfo, currentBounds, SnapPosition.LEFT);
        }

        if (rightTaskId != null) {
            final DesktopModeWindowDecoration decor = mWindowDecorByTaskId.get(rightTaskId);
            final RunningTaskInfo taskInfo = decor.mTaskInfo;
            final Rect currentBounds = taskInfo.configuration.windowConfiguration.getBounds();
            snapPersistedTaskToHalfScreen(taskInfo, currentBounds, SnapPosition.RIGHT);
        }
    }

    @Override
    public void removeTaskIfTiled(int displayId, int taskId) {
        mDesktopTilingDecorViewModel.removeTaskIfTiled(displayId, taskId);
@@ -1008,6 +1032,13 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
        mDesktopTilingDecorViewModel.onDeskDeactivated(deskId);
    }

    @Override
    public void onDisplayDisconnected(int disconnectedDisplayId,
            boolean desktopModeSupportedOnNewDisplay) {
        mDesktopTilingDecorViewModel.onDisplayDisconnected(disconnectedDisplayId,
                desktopModeSupportedOnNewDisplay);
    }

    private class DesktopModeTouchEventListener extends GestureDetector.SimpleOnGestureListener
            implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener,
            View.OnGenericMotionListener, DragDetector.MotionEventHandler {
+36 −0
Original line number Diff line number Diff line
@@ -20,10 +20,12 @@ import android.app.ActivityManager
import android.app.ActivityManager.RunningTaskInfo
import android.content.Context
import android.graphics.Rect
import android.util.ArraySet
import android.util.SparseArray
import android.window.DisplayAreaInfo
import android.window.WindowContainerTransaction
import androidx.core.util.getOrElse
import androidx.core.util.keyIterator
import androidx.core.util.valueIterator
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.protolog.ProtoLog
@@ -75,6 +77,7 @@ class DesktopTilingDecorViewModel(
    @VisibleForTesting
    var tilingHandlerByUserAndDeskId = SparseArray<SparseArray<DesktopTilingWindowDecoration>>()
    var currentUserId: Int = -1
    val disconnectedDisplayDesks = ArraySet<Int>()

    init {
        // TODO(b/374309287): Move this interface implementation to
@@ -180,6 +183,36 @@ 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
        resetAllDesksWithDisplayId(displayId)
    }

    /**
     * Resets tiling sessions for all desks on the disconnected display and retains tiling data if
     * the destination display supports desktop mode, otherwise erases all tiling data.
     */
    fun onDisplayDisconnected(
        disconnectedDisplayId: Int,
        desktopModeSupportedOnNewDisplay: Boolean,
    ) {
        if (!desktopModeSupportedOnNewDisplay) {
            resetAllDesksWithDisplayId(disconnectedDisplayId)
            return
        }
        // Reset the tiling session but keep the persistence data for when the moved desks
        // are activated again.
        for (userHandlerList in tilingHandlerByUserAndDeskId.valueIterator()) {
            for (desk in userHandlerList.keyIterator()) {
                val handler = userHandlerList[desk]
                if (disconnectedDisplayId == handler.displayId) {
                    handler.resetTilingSession(shouldPersistTilingData = true)
                    userHandlerList.remove(desk)
                    disconnectedDisplayDesks.add(desk)
                }
            }
        }
    }

    private fun resetAllDesksWithDisplayId(displayId: Int) {
        for (userHandlerList in tilingHandlerByUserAndDeskId.valueIterator()) {
            for (handler in userHandlerList.valueIterator()) {
                if (displayId == handler.displayId) {
@@ -251,6 +284,9 @@ class DesktopTilingDecorViewModel(
        tilingHandlerByUserAndDeskId[currentUserId]?.get(deskId)?.hideDividerBar()
    }

    /** Removes [deskId] from the previously deactivated desks to mark it's activation. */
    fun onDeskActivated(deskId: Int): Boolean = disconnectedDisplayDesks.remove(deskId)

    fun getCurrentActiveDeskForDisplay(displayId: Int): Int? =
        desktopUserRepositories.current.getActiveDeskId(displayId)

Loading