diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 8ded092f53830..736aa7e9aeca3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -16,14 +16,10 @@ package com.android.wm.shell.desktopmode -import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME import android.content.Context -import android.view.WindowManager -import android.window.WindowContainerTransaction import androidx.annotation.BinderThread import com.android.internal.protolog.common.ProtoLog import com.android.wm.shell.ShellTaskOrganizer -import com.android.wm.shell.common.ExecutorUtils import com.android.wm.shell.common.ExternalInterfaceBinder import com.android.wm.shell.common.RemoteCallable import com.android.wm.shell.common.ShellExecutor @@ -36,7 +32,6 @@ import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.sysui.ShellSharedConstants import com.android.wm.shell.transition.Transitions import java.util.concurrent.Executor -import java.util.function.Consumer /** Handles moving tasks in and out of desktop */ class DesktopTasksController( @@ -67,55 +62,6 @@ class DesktopTasksController( ) } - /** Show all tasks, that are part of the desktop, on top of launcher */ - fun showDesktopApps() { - ProtoLog.v(WM_SHELL_DESKTOP_MODE, "showDesktopApps") - val wct = WindowContainerTransaction() - - bringDesktopAppsToFront(wct) - - // Execute transaction if there are pending operations - if (!wct.isEmpty) { - if (Transitions.ENABLE_SHELL_TRANSITIONS) { - transitions.startTransition(WindowManager.TRANSIT_TO_FRONT, wct, null /* handler */) - } else { - shellTaskOrganizer.applyTransaction(wct) - } - } - } - - private fun bringDesktopAppsToFront(wct: WindowContainerTransaction) { - val activeTasks = desktopModeTaskRepository.getActiveTasks() - - // Skip if all tasks are already visible - if (activeTasks.isNotEmpty() && activeTasks.all(desktopModeTaskRepository::isVisibleTask)) { - ProtoLog.d( - WM_SHELL_DESKTOP_MODE, - "bringDesktopAppsToFront: active tasks are already in front, skipping." - ) - return - } - - ProtoLog.v(WM_SHELL_DESKTOP_MODE, "bringDesktopAppsToFront") - - // First move home to front and then other tasks on top of it - moveHomeTaskToFront(wct) - - val allTasksInZOrder = desktopModeTaskRepository.getFreeformTasksInZOrder() - activeTasks - // Sort descending as the top task is at index 0. It should be ordered to top last - .sortedByDescending { taskId -> allTasksInZOrder.indexOf(taskId) } - .mapNotNull { taskId -> shellTaskOrganizer.getRunningTaskInfo(taskId) } - .forEach { task -> wct.reorder(task.token, true /* onTop */) } - } - - private fun moveHomeTaskToFront(wct: WindowContainerTransaction) { - shellTaskOrganizer - .getRunningTasks(context.displayId) - .firstOrNull { task -> task.activityType == ACTIVITY_TYPE_HOME } - ?.let { homeTask -> wct.reorder(homeTask.getToken(), true /* onTop */) } - } - override fun getContext(): Context { return context } @@ -164,11 +110,7 @@ class DesktopTasksController( } override fun showDesktopApps() { - ExecutorUtils.executeRemoteCallWithTaskPermission( - controller, - "showDesktopApps", - Consumer(DesktopTasksController::showDesktopApps) - ) + // TODO } } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java index cc3916490ba34..b3c9e238a6147 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java @@ -16,6 +16,8 @@ package com.android.wm.shell.desktopmode; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; @@ -26,9 +28,6 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; -import static com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask; -import static com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask; -import static com.android.wm.shell.desktopmode.DesktopTestHelpers.createHomeTask; import static com.google.common.truth.Truth.assertThat; @@ -48,6 +47,7 @@ import android.os.IBinder; import android.testing.AndroidTestingRunner; import android.window.DisplayAreaInfo; import android.window.TransitionRequestInfo; +import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import android.window.WindowContainerTransaction.Change; import android.window.WindowContainerTransaction.HierarchyOp; @@ -58,6 +58,7 @@ import com.android.dx.mockito.inline.extended.StaticMockitoSession; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.TestRunningTaskInfoBuilder; import com.android.wm.shell.TestShellExecutor; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.sysui.ShellController; @@ -353,7 +354,7 @@ public class DesktopModeControllerTest extends ShellTestCase { @Test public void testHandleTransitionRequest_returnsWct() { RunningTaskInfo trigger = new RunningTaskInfo(); - trigger.token = new MockToken().token(); + trigger.token = new MockToken().mToken; trigger.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); WindowContainerTransaction wct = mController.handleRequest( mock(IBinder.class), @@ -368,13 +369,40 @@ public class DesktopModeControllerTest extends ShellTestCase { } private DisplayAreaInfo createMockDisplayArea() { - DisplayAreaInfo displayAreaInfo = new DisplayAreaInfo(new MockToken().token(), + DisplayAreaInfo displayAreaInfo = new DisplayAreaInfo(new MockToken().mToken, mContext.getDisplayId(), 0); when(mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(mContext.getDisplayId())) .thenReturn(displayAreaInfo); return displayAreaInfo; } + private RunningTaskInfo createFreeformTask() { + return new TestRunningTaskInfoBuilder() + .setToken(new MockToken().token()) + .setActivityType(ACTIVITY_TYPE_STANDARD) + .setWindowingMode(WINDOWING_MODE_FREEFORM) + .setLastActiveTime(100) + .build(); + } + + private RunningTaskInfo createFullscreenTask() { + return new TestRunningTaskInfoBuilder() + .setToken(new MockToken().token()) + .setActivityType(ACTIVITY_TYPE_STANDARD) + .setWindowingMode(WINDOWING_MODE_FULLSCREEN) + .setLastActiveTime(100) + .build(); + } + + private RunningTaskInfo createHomeTask() { + return new TestRunningTaskInfoBuilder() + .setToken(new MockToken().token()) + .setActivityType(ACTIVITY_TYPE_HOME) + .setWindowingMode(WINDOWING_MODE_FULLSCREEN) + .setLastActiveTime(100) + .build(); + } + private WindowContainerTransaction getDesktopModeSwitchTransaction() { ArgumentCaptor arg = ArgumentCaptor.forClass( WindowContainerTransaction.class); @@ -402,4 +430,18 @@ public class DesktopModeControllerTest extends ShellTestCase { assertThat(change.getConfiguration().windowConfiguration.getBounds().isEmpty()).isTrue(); } + private static class MockToken { + private final WindowContainerToken mToken; + private final IBinder mBinder; + + MockToken() { + mToken = mock(WindowContainerToken.class); + mBinder = mock(IBinder.class); + when(mToken.asBinder()).thenReturn(mBinder); + } + + WindowContainerToken token() { + return mToken; + } + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index 4e0a5b59cbdcb..15155f80247bf 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -16,10 +16,7 @@ package com.android.wm.shell.desktopmode -import android.app.ActivityManager.RunningTaskInfo import android.testing.AndroidTestingRunner -import android.window.WindowContainerTransaction -import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.android.dx.mockito.inline.extended.ExtendedMockito.never @@ -28,44 +25,39 @@ import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.ShellTestCase import com.android.wm.shell.TestShellExecutor import com.android.wm.shell.common.ShellExecutor -import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask -import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createHomeTask import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.Transitions -import com.google.common.truth.Truth.assertThat -import com.google.common.truth.Truth.assertWithMessage import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentCaptor -import org.mockito.ArgumentMatchers.isNull import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.any -import org.mockito.Mockito.anyInt import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever + @SmallTest @RunWith(AndroidTestingRunner::class) class DesktopTasksControllerTest : ShellTestCase() { - @Mock lateinit var testExecutor: ShellExecutor - @Mock lateinit var shellController: ShellController - @Mock lateinit var shellTaskOrganizer: ShellTaskOrganizer - @Mock lateinit var transitions: Transitions + @Mock + lateinit var testExecutor: ShellExecutor + @Mock + lateinit var shellController: ShellController + @Mock + lateinit var shellTaskOrganizer: ShellTaskOrganizer + @Mock + lateinit var transitions: Transitions lateinit var mockitoSession: StaticMockitoSession lateinit var controller: DesktopTasksController lateinit var shellInit: ShellInit lateinit var desktopModeTaskRepository: DesktopModeTaskRepository - // Mock running tasks are registered here so we can get the list from mock shell task organizer - private val runningTasks = mutableListOf() - @Before fun setUp() { mockitoSession = mockitoSession().mockStatic(DesktopModeStatus::class.java).startMocking() @@ -74,30 +66,19 @@ class DesktopTasksControllerTest : ShellTestCase() { shellInit = Mockito.spy(ShellInit(testExecutor)) desktopModeTaskRepository = DesktopModeTaskRepository() - whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks } - controller = createController() shellInit.init() } private fun createController(): DesktopTasksController { - return DesktopTasksController( - context, - shellInit, - shellController, - shellTaskOrganizer, - transitions, - desktopModeTaskRepository, - TestShellExecutor() - ) + return DesktopTasksController(context, shellInit, shellController, + shellTaskOrganizer, transitions, desktopModeTaskRepository, TestShellExecutor()) } @After fun tearDown() { mockitoSession.finishMocking() - - runningTasks.clear() } @Test @@ -114,111 +95,4 @@ class DesktopTasksControllerTest : ShellTestCase() { verify(shellInit, never()).addInitCallback(any(), any()) } - - @Test - fun showDesktopApps_allAppsInvisible_bringsToFront() { - val homeTask = setUpHomeTask() - val task1 = setUpDesktopTask() - val task2 = setUpDesktopTask() - markTaskHidden(task1) - markTaskHidden(task2) - - controller.showDesktopApps() - - val wct = getLatestWct() - assertThat(wct.hierarchyOps).hasSize(3) - // Expect order to be from bottom: home, task1, task2 - wct.assertReorderAt(index = 0, homeTask) - wct.assertReorderAt(index = 1, task1) - wct.assertReorderAt(index = 2, task2) - } - - @Test - fun showDesktopApps_appsAlreadyVisible_doesNothing() { - setUpHomeTask() - val task1 = setUpDesktopTask() - val task2 = setUpDesktopTask() - markTaskVisible(task1) - markTaskVisible(task2) - - controller.showDesktopApps() - - if (Transitions.ENABLE_SHELL_TRANSITIONS) { - verify(transitions, never()).startTransition(anyInt(), any(), isNull()) - } else { - verify(shellTaskOrganizer, never()).applyTransaction(any()) - } - } - - @Test - fun showDesktopApps_someAppsInvisible_reordersAll() { - val homeTask = setUpHomeTask() - val task1 = setUpDesktopTask() - val task2 = setUpDesktopTask() - markTaskHidden(task1) - markTaskVisible(task2) - - controller.showDesktopApps() - - val wct = getLatestWct() - assertThat(wct.hierarchyOps).hasSize(3) - // Expect order to be from bottom: home, task1, task2 - wct.assertReorderAt(index = 0, homeTask) - wct.assertReorderAt(index = 1, task1) - wct.assertReorderAt(index = 2, task2) - } - - @Test - fun showDesktopApps_noActiveTasks_reorderHomeToTop() { - val homeTask = setUpHomeTask() - - controller.showDesktopApps() - - val wct = getLatestWct() - assertThat(wct.hierarchyOps).hasSize(1) - wct.assertReorderAt(index = 0, homeTask) - } - - private fun setUpDesktopTask(): RunningTaskInfo { - val task = createFreeformTask() - whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task) - desktopModeTaskRepository.addActiveTask(task.taskId) - desktopModeTaskRepository.addOrMoveFreeformTaskToTop(task.taskId) - runningTasks.add(task) - return task - } - - private fun setUpHomeTask(): RunningTaskInfo { - val task = createHomeTask() - whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task) - runningTasks.add(task) - return task - } - - private fun markTaskVisible(task: RunningTaskInfo) { - desktopModeTaskRepository.updateVisibleFreeformTasks(task.taskId, visible = true) - } - - private fun markTaskHidden(task: RunningTaskInfo) { - desktopModeTaskRepository.updateVisibleFreeformTasks(task.taskId, visible = false) - } - - private fun getLatestWct(): WindowContainerTransaction { - val arg = ArgumentCaptor.forClass(WindowContainerTransaction::class.java) - if (Transitions.ENABLE_SHELL_TRANSITIONS) { - verify(transitions).startTransition(anyInt(), arg.capture(), isNull()) - } else { - verify(shellTaskOrganizer).applyTransaction(arg.capture()) - } - return arg.value - } -} - -private fun WindowContainerTransaction.assertReorderAt(index: Int, task: RunningTaskInfo) { - assertWithMessage("WCT does not have a hierarchy operation at index $index") - .that(hierarchyOps.size) - .isGreaterThan(index) - val op = hierarchyOps[index] - assertThat(op.type).isEqualTo(HIERARCHY_OP_TYPE_REORDER) - assertThat(op.container).isEqualTo(task.token.asBinder()) -} +} \ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt deleted file mode 100644 index dc91d756842ec..0000000000000 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.desktopmode - -import android.app.ActivityManager.RunningTaskInfo -import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME -import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD -import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM -import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN -import com.android.wm.shell.TestRunningTaskInfoBuilder - -class DesktopTestHelpers { - companion object { - /** Create a task that has windowing mode set to [WINDOWING_MODE_FREEFORM] */ - @JvmStatic - fun createFreeformTask(): RunningTaskInfo { - return TestRunningTaskInfoBuilder() - .setToken(MockToken().token()) - .setActivityType(ACTIVITY_TYPE_STANDARD) - .setWindowingMode(WINDOWING_MODE_FREEFORM) - .setLastActiveTime(100) - .build() - } - - /** Create a task that has windowing mode set to [WINDOWING_MODE_FULLSCREEN] */ - @JvmStatic - fun createFullscreenTask(): RunningTaskInfo { - return TestRunningTaskInfoBuilder() - .setToken(MockToken().token()) - .setActivityType(ACTIVITY_TYPE_STANDARD) - .setWindowingMode(WINDOWING_MODE_FULLSCREEN) - .setLastActiveTime(100) - .build() - } - - /** Create a new home task */ - @JvmStatic - fun createHomeTask(): RunningTaskInfo { - return TestRunningTaskInfoBuilder() - .setToken(MockToken().token()) - .setActivityType(ACTIVITY_TYPE_HOME) - .setWindowingMode(WINDOWING_MODE_FULLSCREEN) - .setLastActiveTime(100) - .build() - } - } -} \ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/MockToken.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/MockToken.java deleted file mode 100644 index 09d474d1f97c4..0000000000000 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/MockToken.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.desktopmode; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import android.os.IBinder; -import android.window.WindowContainerToken; - -/** - * {@link WindowContainerToken} wrapper that supports a mock binder - */ -class MockToken { - private final WindowContainerToken mToken; - - MockToken() { - mToken = mock(WindowContainerToken.class); - IBinder binder = mock(IBinder.class); - when(mToken.asBinder()).thenReturn(binder); - } - - WindowContainerToken token() { - return mToken; - } -}