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

Commit 9a372e7c authored by Orhan Uysal's avatar Orhan Uysal Committed by Android (Google) Code Review
Browse files

Merge "Add moving a task from recents to desktop" into main

parents 52ad3e2a b58db4c1
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -522,14 +522,16 @@ public abstract class WMShellModule {
            RecentsTransitionHandler recentsTransitionHandler,
            MultiInstanceHelper multiInstanceHelper,
            @ShellMainThread ShellExecutor mainExecutor,
            Optional<DesktopTasksLimiter> desktopTasksLimiter) {
            Optional<DesktopTasksLimiter> desktopTasksLimiter,
            Optional<RecentTasksController> recentTasksController) {
        return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController,
                displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer,
                dragAndDropController, transitions, enterDesktopTransitionHandler,
                exitDesktopTransitionHandler, toggleResizeDesktopTaskTransitionHandler,
                dragToDesktopTransitionHandler, desktopModeTaskRepository,
                desktopModeLoggerTransitionObserver, launchAdjacentController,
                recentsTransitionHandler, multiInstanceHelper, mainExecutor, desktopTasksLimiter);
                recentsTransitionHandler, multiInstanceHelper,
                mainExecutor, desktopTasksLimiter, recentTasksController.orElse(null));
    }

    @WMSingleton
+38 −11
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksLi
import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.DragToDesktopStateListener
import com.android.wm.shell.draganddrop.DragAndDropController
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
import com.android.wm.shell.recents.RecentTasksController
import com.android.wm.shell.recents.RecentsTransitionHandler
import com.android.wm.shell.recents.RecentsTransitionStateListener
import com.android.wm.shell.shared.DesktopModeStatus
@@ -118,6 +119,7 @@ class DesktopTasksController(
    private val multiInstanceHelper: MultiInstanceHelper,
    @ShellMainThread private val mainExecutor: ShellExecutor,
    private val desktopTasksLimiter: Optional<DesktopTasksLimiter>,
    private val recentTasksController: RecentTasksController?
) :
    RemoteCallable<DesktopTasksController>,
    Transitions.TransitionHandler,
@@ -293,24 +295,49 @@ class DesktopTasksController(
        taskId: Int,
        wct: WindowContainerTransaction = WindowContainerTransaction()
    ): Boolean {
        shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { task -> moveToDesktop(task, wct) }
            ?: return false
        shellTaskOrganizer.getRunningTaskInfo(taskId)?.let {
            moveToDesktop(it, wct)
        } ?: moveToDesktopFromNonRunningTask(taskId, wct)
        return true
    }

    /** Move a task to desktop */
    private fun moveToDesktopFromNonRunningTask(
        taskId: Int,
        wct: WindowContainerTransaction
    ): Boolean {
        recentTasksController?.findTaskInBackground(taskId)?.let {
            KtProtoLog.v(
                WM_SHELL_DESKTOP_MODE,
                "DesktopTasksController: moveToDesktopFromNonRunningTask taskId=%d",
                taskId
            )
            // TODO(342378842): Instead of using default display, support multiple displays
            val taskToMinimize =
                bringDesktopAppsToFrontBeforeShowingNewTask(DEFAULT_DISPLAY, wct, taskId)
            addMoveToDesktopChangesNonRunningTask(wct, taskId)
            // TODO(343149901): Add DPI changes for task launch
            val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct)
            addPendingMinimizeTransition(transition, taskToMinimize)
            return true
        } ?: return false
    }

    private fun addMoveToDesktopChangesNonRunningTask(
        wct: WindowContainerTransaction,
        taskId: Int
    ) {
        val options = ActivityOptions.makeBasic()
        options.launchWindowingMode = WINDOWING_MODE_FREEFORM
        wct.startTask(taskId, options.toBundle())
    }

    /**
     * Move a task to desktop
     */
    fun moveToDesktop(
        task: RunningTaskInfo,
        wct: WindowContainerTransaction = WindowContainerTransaction()
    ) {
        if (!DesktopModeStatus.canEnterDesktopMode(context)) {
            KtProtoLog.w(
                WM_SHELL_DESKTOP_MODE,
                "DesktopTasksController: Cannot enter desktop, " +
                    "display does not meet minimum size requirements"
            )
            return
        }
        if (Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task)) {
            KtProtoLog.w(
                WM_SHELL_DESKTOP_MODE,
+19 −0
Original line number Diff line number Diff line
@@ -446,6 +446,25 @@ public class RecentTasksController implements TaskStackListenerCallback,
        return null;
    }

    /**
     * Find the background task that match the given taskId.
     */
    @Nullable
    public ActivityManager.RecentTaskInfo findTaskInBackground(int taskId) {
        List<ActivityManager.RecentTaskInfo> tasks = mActivityTaskManager.getRecentTasks(
                Integer.MAX_VALUE, ActivityManager.RECENT_IGNORE_UNAVAILABLE,
                ActivityManager.getCurrentUser());
        for (int i = 0; i < tasks.size(); i++) {
            final ActivityManager.RecentTaskInfo task = tasks.get(i);
            if (task.isVisible) {
                continue;
            }
            if (taskId == task.taskId) {
                return task;
            }
        }
        return null;
    }
    public void dump(@NonNull PrintWriter pw, String prefix) {
        final String innerPrefix = prefix + "  ";
        pw.println(prefix + TAG);
+47 −8
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.wm.shell.desktopmode

import android.app.ActivityManager.RecentTaskInfo
import android.app.ActivityManager.RunningTaskInfo
import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
@@ -47,13 +48,16 @@ import android.view.WindowManager.TRANSIT_OPEN
import android.view.WindowManager.TRANSIT_TO_BACK
import android.view.WindowManager.TRANSIT_TO_FRONT
import android.window.DisplayAreaInfo
import android.window.IWindowContainerToken
import android.window.RemoteTransition
import android.window.TransitionRequestInfo
import android.window.WindowContainerToken
import android.window.WindowContainerTransaction
import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_LAUNCH_TASK
import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT
import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_TASK
import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER
import android.window.WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
@@ -78,6 +82,7 @@ import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFulls
import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createHomeTask
import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createSplitScreenTask
import com.android.wm.shell.draganddrop.DragAndDropController
import com.android.wm.shell.recents.RecentTasksController
import com.android.wm.shell.recents.RecentsTransitionHandler
import com.android.wm.shell.recents.RecentsTransitionStateListener
import com.android.wm.shell.shared.DesktopModeStatus
@@ -93,6 +98,7 @@ import com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_DESKTOP_MODE
import com.android.wm.shell.transition.Transitions.TransitionHandler
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import java.util.Optional
import org.junit.After
import org.junit.Assume.assumeTrue
import org.junit.Before
@@ -115,7 +121,6 @@ import org.mockito.kotlin.anyOrNull
import org.mockito.kotlin.atLeastOnce
import org.mockito.kotlin.capture
import org.mockito.quality.Strictness
import java.util.Optional
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.mockito.Mockito.`when` as whenever
@@ -154,6 +159,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
    @Mock lateinit var multiInstanceHelper: MultiInstanceHelper
    @Mock lateinit var desktopModeLoggerTransitionObserver: DesktopModeLoggerTransitionObserver
    @Mock lateinit var desktopModeVisualIndicator: DesktopModeVisualIndicator
    @Mock lateinit var recentTasksController: RecentTasksController

    private lateinit var mockitoSession: StaticMockitoSession
    private lateinit var controller: DesktopTasksController
@@ -233,6 +239,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
            multiInstanceHelper,
            shellExecutor,
            Optional.of(desktopTasksLimiter),
            recentTasksController
        )
    }

@@ -643,14 +650,17 @@ class DesktopTasksControllerTest : ShellTestCase() {
    }

    @Test
    fun moveToDesktop_deviceNotSupported_doesNothing() {
        val task = setUpFullscreenTask()
    fun moveToDesktop_nonRunningTask_launchesInFreeform() {
        whenever(shellTaskOrganizer.getRunningTaskInfo(anyInt())).thenReturn(null)

        // Simulate non compatible device
        doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
        val task = createTaskInfo(1)

        controller.moveToDesktop(task)
        verifyWCTNotExecuted()
        whenever(recentTasksController.findTaskInBackground(anyInt())).thenReturn(task)

        controller.moveToDesktop(task.taskId)
        with(getLatestMoveToDesktopWct()){
            assertLaunchTaskAt(0, task.taskId, WINDOWING_MODE_FREEFORM)
        }
    }

    @Test
@@ -665,6 +675,17 @@ class DesktopTasksControllerTest : ShellTestCase() {
        verifyWCTNotExecuted()
    }

    @Test
    fun moveToDesktop_deviceNotSupported_doesNothing() {
        val task = setUpFullscreenTask()

        // Simulate non compatible device
        doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }

        controller.moveToDesktop(task)
        verifyWCTNotExecuted()
    }

    @Test
    fun moveToDesktop_deviceNotSupported_deviceRestrictionsOverridden_taskIsMovedToDesktop() {
        val task = setUpFullscreenTask()
@@ -1834,6 +1855,20 @@ private fun WindowContainerTransaction.assertPendingIntentAt(index: Int, intent:
    assertThat(op.pendingIntent?.intent?.component).isEqualTo(intent.component)
}

private fun WindowContainerTransaction.assertLaunchTaskAt(
    index: Int,
    taskId: Int,
    windowingMode: Int
) {
    val keyLaunchWindowingMode = "android.activity.windowingMode"

    assertIndexInBounds(index)
    val op = hierarchyOps[index]
    assertThat(op.type).isEqualTo(HIERARCHY_OP_TYPE_LAUNCH_TASK)
    assertThat(op.launchOptions?.getInt(LAUNCH_KEY_TASK_ID)).isEqualTo(taskId)
    assertThat(op.launchOptions?.getInt(keyLaunchWindowingMode, WINDOWING_MODE_UNDEFINED))
            .isEqualTo(windowingMode)
}
private fun WindowContainerTransaction?.anyDensityConfigChange(
    token: WindowContainerToken
): Boolean {
@@ -1841,3 +1876,7 @@ private fun WindowContainerTransaction?.anyDensityConfigChange(
        change.key == token.asBinder() && ((change.value.configSetMask and CONFIG_DENSITY) != 0)
    } ?: false
}
private fun createTaskInfo(id: Int) = RecentTaskInfo().apply {
    taskId = id
    token = WindowContainerToken(mock(IWindowContainerToken::class.java))
}