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

Commit 72ddf9b3 authored by Jagrut Desai's avatar Jagrut Desai Committed by Android (Google) Code Review
Browse files

Merge "Adding callback support for Entering/Exiting DesktopMode" into main

parents ae1f3b4f c10cdc75
Loading
Loading
Loading
Loading
+74 −24
Original line number Diff line number Diff line
@@ -127,6 +127,10 @@ import java.util.Optional
import java.util.concurrent.Executor
import java.util.function.Consumer
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.Companion.DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS
import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION
import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler.FULLSCREEN_ANIMATION_DURATION

/** Handles moving tasks in and out of desktop */
class DesktopTasksController(
    private val context: Context,
@@ -195,6 +199,9 @@ class DesktopTasksController(
    @VisibleForTesting
    var taskbarDesktopTaskListener: TaskbarDesktopTaskListener? = null

    @VisibleForTesting
    var desktopModeEnterExitTransitionListener: DesktopModeEntryExitTransitionListener? = null

    /** Task id of the task currently being dragged from fullscreen/split. */
    val draggingTaskId
        get() = dragToDesktopTransitionHandler.draggingTaskId
@@ -380,6 +387,7 @@ class DesktopTasksController(
        )
        // TODO(343149901): Add DPI changes for task launch
        val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource)
        desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
        taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
        exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
        return true
@@ -409,6 +417,7 @@ class DesktopTasksController(
        addMoveToDesktopChanges(wct, task)

        val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource)
        desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
        taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
        exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
    }
@@ -450,6 +459,9 @@ class DesktopTasksController(
        val exitResult = desktopImmersiveController.exitImmersiveIfApplicable(
            wct, taskInfo.displayId)
        val transition = dragToDesktopTransitionHandler.finishDragToDesktopTransition(wct)
        desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted(
            DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS.toInt()
        )
        transition?.let {
            taskIdToMinimize?.let { taskId -> addPendingMinimizeTransition(it, taskId) }
            exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
@@ -485,9 +497,7 @@ class DesktopTasksController(
    ): ((IBinder) -> Unit)? {
        val taskId = taskInfo.taskId
        desktopTilingDecorViewModel.removeTaskIfTiled(displayId, taskId)
        if (taskRepository.isOnlyVisibleNonClosingTask(taskId)) {
            removeWallpaperActivity(wct)
        }
        performDesktopExitCleanupIfNeeded(taskId, wct)
        taskRepository.addClosingTask(displayId, taskId)
        taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
            doesAnyTaskRequireTaskbarRounding(
@@ -503,11 +513,7 @@ class DesktopTasksController(
        val taskId = taskInfo.taskId
        val displayId = taskInfo.displayId
        val wct = WindowContainerTransaction()
        if (taskRepository.isOnlyVisibleNonClosingTask(taskId)) {
            // Perform clean up of the desktop wallpaper activity if the minimized window task is
            // the last active task.
            removeWallpaperActivity(wct)
        }
        performDesktopExitCleanupIfNeeded(taskId, wct)
        // Notify immersive handler as it might need to exit immersive state.
        val exitResult = desktopImmersiveController.exitImmersiveIfApplicable(wct, taskInfo)

@@ -576,6 +582,11 @@ class DesktopTasksController(
                position,
                mOnAnimationFinishedCallback
            )

        // handles case where we are moving to full screen without closing all DW tasks.
        if (!taskRepository.isOnlyVisibleNonClosingTask(task.taskId)) {
            desktopModeEnterExitTransitionListener?.onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
        }
    }

    /**
@@ -1226,6 +1237,21 @@ class DesktopTasksController(
        }
    }

    /**
     * Remove wallpaper activity if task provided is last task and wallpaper activity token is not
     * null
     */
    private fun performDesktopExitCleanupIfNeeded(taskId: Int, wct: WindowContainerTransaction) {
        if (!taskRepository.isOnlyVisibleNonClosingTask(taskId)) {
            return
        }
        desktopModeEnterExitTransitionListener?.onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
        if (taskRepository.wallpaperActivityToken != null) {
            removeWallpaperActivity(wct)
        }
    }


    fun releaseVisualIndicator() {
        val t = SurfaceControl.Transaction()
        visualIndicator?.releaseVisualIndicator(t)
@@ -1662,12 +1688,7 @@ class DesktopTasksController(
            return null

        val wct = WindowContainerTransaction()
        if (taskRepository.isOnlyVisibleNonClosingTask(task.taskId)
            && taskRepository.wallpaperActivityToken != null
        ) {
            // Remove wallpaper activity when the last active task is removed
            removeWallpaperActivity(wct)
        }
        performDesktopExitCleanupIfNeeded(task.taskId, wct)

        if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()) {
            taskRepository.addClosingTask(task.displayId, task.taskId)
@@ -1758,10 +1779,8 @@ class DesktopTasksController(
        if (useDesktopOverrideDensity()) {
            wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi())
        }
        if (taskRepository.isOnlyVisibleNonClosingTask(taskInfo.taskId)) {
            // Remove wallpaper activity when leaving desktop mode
            removeWallpaperActivity(wct)
        }

        performDesktopExitCleanupIfNeeded(taskInfo.taskId, wct)
    }

    private fun cascadeWindow(bounds: Rect, displayLayout: DisplayLayout, displayId: Int) {
@@ -1790,10 +1809,8 @@ class DesktopTasksController(
        // The task's density may have been overridden in freeform; revert it here as we don't
        // want it overridden in multi-window.
        wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi())
        if (taskRepository.isOnlyVisibleNonClosingTask(taskInfo.taskId)) {
            // Remove wallpaper activity when leaving desktop mode
            removeWallpaperActivity(wct)
        }

        performDesktopExitCleanupIfNeeded(taskInfo.taskId, wct)
    }

    /** Returns the ID of the Task that will be minimized, or null if no task will be minimized. */
@@ -2331,7 +2348,7 @@ class DesktopTasksController(
                }
            }

        private val mTaskbarDesktopTaskListener: TaskbarDesktopTaskListener =
        private val taskbarDesktopTaskListener: TaskbarDesktopTaskListener =
                object : TaskbarDesktopTaskListener {
                    override fun onTaskbarCornerRoundingUpdate(
                        hasTasksRequiringTaskbarRounding: Boolean) {
@@ -2348,6 +2365,27 @@ class DesktopTasksController(
                    }
                }

        private val desktopModeEntryExitTransitionListener: DesktopModeEntryExitTransitionListener =
            object : DesktopModeEntryExitTransitionListener {
                override fun onEnterDesktopModeTransitionStarted(transitionDuration: Int) {
                    ProtoLog.v(
                        WM_SHELL_DESKTOP_MODE,
                        "IDesktopModeImpl: onEnterDesktopModeTransitionStarted transitionTime=%s",
                        transitionDuration
                    )
                    remoteListener.call { l -> l.onEnterDesktopModeTransitionStarted(transitionDuration) }
                }

                override fun onExitDesktopModeTransitionStarted(transitionDuration: Int) {
                    ProtoLog.v(
                        WM_SHELL_DESKTOP_MODE,
                        "IDesktopModeImpl: onExitDesktopModeTransitionStarted transitionTime=%s",
                        transitionDuration
                    )
                    remoteListener.call { l -> l.onExitDesktopModeTransitionStarted(transitionDuration) }
                }
            }

        init {
            remoteListener =
                SingleInstanceRemoteListener<DesktopTasksController, IDesktopTaskListener>(
@@ -2355,13 +2393,16 @@ class DesktopTasksController(
                    { c ->
                        run {
                            c.taskRepository.addVisibleTasksListener(listener, c.mainExecutor)
                            c.taskbarDesktopTaskListener = mTaskbarDesktopTaskListener
                            c.taskbarDesktopTaskListener = taskbarDesktopTaskListener
                            c.desktopModeEnterExitTransitionListener =
                                desktopModeEntryExitTransitionListener
                        }
                    },
                    { c ->
                        run {
                            c.taskRepository.removeVisibleTasksListener(listener)
                            c.taskbarDesktopTaskListener = null
                            c.desktopModeEnterExitTransitionListener = null
                        }
                    }
                )
@@ -2468,6 +2509,15 @@ class DesktopTasksController(
        fun onTaskbarCornerRoundingUpdate(hasTasksRequiringTaskbarRounding: Boolean)
    }

    /** Defines interface for entering and exiting desktop windowing mode. */
    interface DesktopModeEntryExitTransitionListener {
        /** [transitionDuration] time it takes to run enter desktop mode transition */
        fun onEnterDesktopModeTransitionStarted(transitionDuration: Int)

        /** [transitionDuration] time it takes to run exit desktop mode transition */
        fun onExitDesktopModeTransitionStarted(transitionDuration: Int)
    }

    /** The positions on a screen that a task can snap to. */
    enum class SnapPosition {
        RIGHT,
+1 −2
Original line number Diff line number Diff line
@@ -60,8 +60,7 @@ import java.util.function.Supplier;
 * entering and exiting freeform.
 */
public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionHandler {
    @VisibleForTesting
    static final int FULLSCREEN_ANIMATION_DURATION = 336;
    public static final int FULLSCREEN_ANIMATION_DURATION = 336;

    private final Context mContext;
    private final Transitions mTransitions;
+6 −0
Original line number Diff line number Diff line
@@ -33,4 +33,10 @@ interface IDesktopTaskListener {
     * [hasTasksRequiringTaskbarRounding] is true.
     */
    oneway void onTaskbarCornerRoundingUpdate(boolean hasTasksRequiringTaskbarRounding);

    /** Entering desktop mode transition is started, send the signal with transition duration. */
    oneway void onEnterDesktopModeTransitionStarted(int transitionDuration);

    /** Exiting desktop mode transition is started, send the signal with transition duration. */
    oneway void onExitDesktopModeTransitionStarted(int transitionDuration);
}
 No newline at end of file
+27 −2
Original line number Diff line number Diff line
@@ -95,12 +95,15 @@ import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.desktopmode.DesktopImmersiveController.ExitResult
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger
import com.android.wm.shell.desktopmode.DesktopTasksController.DesktopModeEntryExitTransitionListener
import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition
import com.android.wm.shell.desktopmode.DesktopTasksController.TaskbarDesktopTaskListener
import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask
import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createHomeTask
import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createSplitScreenTask
import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION
import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler.FULLSCREEN_ANIMATION_DURATION
import com.android.wm.shell.desktopmode.minimize.DesktopWindowLimitRemoteHandler
import com.android.wm.shell.desktopmode.persistence.Desktop
import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
@@ -223,6 +226,8 @@ class DesktopTasksControllerTest : ShellTestCase() {
  @Mock
  private lateinit var desktopWindowDecoration: DesktopModeWindowDecoration
  @Mock private lateinit var resources: Resources
  @Mock
  lateinit var desktopModeEnterExitTransitionListener: DesktopModeEntryExitTransitionListener
  private lateinit var controller: DesktopTasksController
  private lateinit var shellInit: ShellInit
  private lateinit var taskRepository: DesktopRepository
@@ -294,6 +299,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
    controller = createController()
    controller.setSplitScreenController(splitScreenController)
    controller.freeformTaskTransitionStarter = freeformTaskTransitionStarter
    controller.desktopModeEnterExitTransitionListener = desktopModeEnterExitTransitionListener

    shellInit.init()

@@ -1054,6 +1060,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
    controller.moveRunningTaskToDesktop(task, transitionSource = UNKNOWN)
    val wct = getLatestEnterDesktopWct()
    assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
  }

  @Test
@@ -1065,12 +1072,14 @@ class DesktopTasksControllerTest : ShellTestCase() {
    val wct = getLatestEnterDesktopWct()
    assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
        .isEqualTo(WINDOWING_MODE_UNDEFINED)
    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
  }

  @Test
  fun moveTaskToDesktop_nonExistentTask_doesNothing() {
    controller.moveTaskToDesktop(999, transitionSource = UNKNOWN)
    verifyEnterDesktopWCTNotExecuted()
    verify(desktopModeEnterExitTransitionListener, times(0)).onEnterDesktopModeTransitionStarted(anyInt())
  }

  @Test
@@ -1115,9 +1124,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
      }

    controller.moveRunningTaskToDesktop(task, transitionSource = UNKNOWN)

    val wct = getLatestEnterDesktopWct()
    assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
  }

  @Test
@@ -1132,6 +1141,9 @@ class DesktopTasksControllerTest : ShellTestCase() {

    controller.moveRunningTaskToDesktop(task, transitionSource = UNKNOWN)
    verifyEnterDesktopWCTNotExecuted()
    verify(desktopModeEnterExitTransitionListener, times(0)).onEnterDesktopModeTransitionStarted(
      FREEFORM_ANIMATION_DURATION
    )
  }

  @Test
@@ -1178,6 +1190,7 @@ class DesktopTasksControllerTest : ShellTestCase() {

    val wct = getLatestEnterDesktopWct()
    assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
  }

  @Test
@@ -1197,6 +1210,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
      assertThat(changes[fullscreenTask.token.asBinder()]?.windowingMode)
          .isEqualTo(WINDOWING_MODE_FREEFORM)
    }
    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
  }

  @Test
@@ -1217,6 +1231,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
      assertThat(changes[fullscreenTask.token.asBinder()]?.windowingMode)
          .isEqualTo(WINDOWING_MODE_FREEFORM)
    }
    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
  }

  @Test
@@ -1238,6 +1253,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
      assertThat(hierarchyOps.map { it.container })
          .doesNotContain(freeformTaskSecond.token.asBinder())
    }
    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
  }

  @Test
@@ -1246,6 +1262,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
    controller.moveRunningTaskToDesktop(task, transitionSource = UNKNOWN)
    val wct = getLatestEnterDesktopWct()
    assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
    verify(splitScreenController)
        .prepareExitSplitScreen(any(), anyInt(), eq(SplitScreenController.EXIT_REASON_DESKTOP_MODE))
  }
@@ -1256,6 +1273,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
    controller.moveRunningTaskToDesktop(task, transitionSource = UNKNOWN)
    val wct = getLatestEnterDesktopWct()
    assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
    verify(splitScreenController, never())
        .prepareExitSplitScreen(any(), anyInt(), eq(SplitScreenController.EXIT_REASON_DESKTOP_MODE))
  }
@@ -1270,6 +1288,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
    controller.moveRunningTaskToDesktop(newTask, transitionSource = UNKNOWN)

    val wct = getLatestEnterDesktopWct()
    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
    assertThat(wct.hierarchyOps.size).isEqualTo(MAX_TASK_LIMIT + 1) // visible tasks + home
    wct.assertReorderAt(0, homeTask)
    wct.assertReorderSequenceInRange(
@@ -1288,6 +1307,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
    controller.moveRunningTaskToDesktop(newTask, transitionSource = UNKNOWN)

    val wct = getLatestEnterDesktopWct()
    verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION)
    assertThat(wct.hierarchyOps.size).isEqualTo(MAX_TASK_LIMIT + 2) // tasks + home + wallpaper
    // Move home to front
    wct.assertReorderAt(0, homeTask)
@@ -1307,6 +1327,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
    tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN
    controller.moveToFullscreen(task.taskId, transitionSource = UNKNOWN)
    val wct = getLatestExitDesktopWct()
    verify(desktopModeEnterExitTransitionListener, times(1)).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
    assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
        .isEqualTo(WINDOWING_MODE_UNDEFINED)
  }
@@ -1324,6 +1345,7 @@ class DesktopTasksControllerTest : ShellTestCase() {

    val wct = getLatestExitDesktopWct()
    val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
    verify(desktopModeEnterExitTransitionListener).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
    assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED)
    // Removes wallpaper activity when leaving desktop
    wct.assertRemoveAt(index = 0, wallpaperToken)
@@ -1338,6 +1360,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
    val wct = getLatestExitDesktopWct()
    assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
        .isEqualTo(WINDOWING_MODE_FULLSCREEN)
    verify(desktopModeEnterExitTransitionListener).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
  }

  @Test
@@ -1354,6 +1377,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
    val wct = getLatestExitDesktopWct()
    val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
    assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_FULLSCREEN)
    verify(desktopModeEnterExitTransitionListener).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
    // Removes wallpaper activity when leaving desktop
    wct.assertRemoveAt(index = 0, wallpaperToken)
  }
@@ -1374,6 +1398,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
    val wct = getLatestExitDesktopWct()
    val task1Change = assertNotNull(wct.changes[task1.token.asBinder()])
    assertThat(task1Change.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED)
    verify(desktopModeEnterExitTransitionListener).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
    // Does not remove wallpaper activity, as desktop still has a visible desktop task
    assertThat(wct.hierarchyOps).isEmpty()
  }
@@ -1388,13 +1413,13 @@ class DesktopTasksControllerTest : ShellTestCase() {
  fun moveToFullscreen_secondDisplayTaskHasFreeform_secondDisplayNotAffected() {
    val taskDefaultDisplay = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
    val taskSecondDisplay = setUpFreeformTask(displayId = SECOND_DISPLAY)

    controller.moveToFullscreen(taskDefaultDisplay.taskId, transitionSource = UNKNOWN)

    with(getLatestExitDesktopWct()) {
      assertThat(changes.keys).contains(taskDefaultDisplay.token.asBinder())
      assertThat(changes.keys).doesNotContain(taskSecondDisplay.token.asBinder())
    }
    verify(desktopModeEnterExitTransitionListener).onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
  }

  @Test