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

Commit 6fadd913 authored by Patrick Chang's avatar Patrick Chang
Browse files

Revert "Implement showDesktopApps"

Revert submission 20653722

Reason for revert: DroidMonitor-triggered revert due to breakage <link to breakage in Quarterdeck>, bug b/262303930.
Reverted Changes: 
BUG: <breakage bug #>
I0435e07a2:Create controller for desktop prototype 2
I9907038ad:Implement move to desktop and fullscreen
Ic5de4d431:Implement showDesktopApps

Change-Id: Ia04d63dd0d9506b7b6d874883b5d0d69585b03ad
parent 27ab8c08
Loading
Loading
Loading
Loading
+1 −59
Original line number Diff line number Diff line
@@ -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
        }
    }
}
+47 −5
Original line number Diff line number Diff line
@@ -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<WindowContainerTransaction> 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;
        }
    }
}
+12 −138
Original line number Diff line number Diff line
@@ -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<RunningTaskInfo>()

    @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<DesktopTasksController>())
    }

    @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
+0 −61
Original line number Diff line number Diff line
/*
 * 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
+0 −40
Original line number Diff line number Diff line
/*
 * 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;
    }
}