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

Commit fc558746 authored by Ats Jenk's avatar Ats Jenk
Browse files

Move desktop mode logic out of ShellTaskOrganizer

Expose list of running tasks per display from ShellTaskOrganizer.
This allows us to move desktop mode related logic out from
ShellTaskOrganizer and to DesktopModeController.

Bug: 258282673
Test: atest DesktopModeControllerTest ShellTaskOrganizerTests
Change-Id: I179c69c185153a07de3602627ed18734420abda2
parent dcb12923
Loading
Loading
Loading
Loading
+16 −54
Original line number Diff line number Diff line
@@ -16,14 +16,12 @@

package com.android.wm.shell;

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_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;

import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;

@@ -48,7 +46,6 @@ import android.window.StartingWindowInfo;
import android.window.StartingWindowRemovalInfo;
import android.window.TaskAppearedInfo;
import android.window.TaskOrganizer;
import android.window.WindowContainerTransaction;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
@@ -567,6 +564,22 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
        }
    }

    /**
     * Return list of {@link RunningTaskInfo}s for the given display.
     *
     * @return filtered list of tasks or empty list
     */
    public ArrayList<RunningTaskInfo> getRunningTasks(int displayId) {
        ArrayList<RunningTaskInfo> result = new ArrayList<>();
        for (int i = 0; i < mTasks.size(); i++) {
            RunningTaskInfo taskInfo = mTasks.valueAt(i).getTaskInfo();
            if (taskInfo.displayId == displayId) {
                result.add(taskInfo);
            }
        }
        return result;
    }

    /** Gets running task by taskId. Returns {@code null} if no such task observed. */
    @Nullable
    public RunningTaskInfo getRunningTaskInfo(int taskId) {
@@ -693,57 +706,6 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
        taskListener.reparentChildSurfaceToTask(taskId, sc, t);
    }

    /**
     * Create a {@link WindowContainerTransaction} to clear task bounds.
     *
     * Only affects tasks that have {@link RunningTaskInfo#getActivityType()} set to
     * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
     *
     * @param displayId display id for tasks that will have bounds cleared
     * @return {@link WindowContainerTransaction} with pending operations to clear bounds
     */
    public WindowContainerTransaction prepareClearBoundsForStandardTasks(int displayId) {
        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "prepareClearBoundsForTasks: displayId=%d", displayId);
        WindowContainerTransaction wct = new WindowContainerTransaction();
        for (int i = 0; i < mTasks.size(); i++) {
            RunningTaskInfo taskInfo = mTasks.valueAt(i).getTaskInfo();
            if ((taskInfo.displayId == displayId) && (taskInfo.getActivityType()
                    == WindowConfiguration.ACTIVITY_TYPE_STANDARD)) {
                ProtoLog.d(WM_SHELL_DESKTOP_MODE, "clearing bounds for token=%s taskInfo=%s",
                        taskInfo.token, taskInfo);
                wct.setBounds(taskInfo.token, null);
            }
        }
        return wct;
    }

    /**
     * Create a {@link WindowContainerTransaction} to clear task level freeform setting.
     *
     * Only affects tasks that have {@link RunningTaskInfo#getActivityType()} set to
     * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
     *
     * @param displayId display id for tasks that will have windowing mode reset to {@link
     *                  WindowConfiguration#WINDOWING_MODE_UNDEFINED}
     * @return {@link WindowContainerTransaction} with pending operations to clear windowing mode
     */
    public WindowContainerTransaction prepareClearFreeformForStandardTasks(int displayId) {
        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "prepareClearFreeformForTasks: displayId=%d", displayId);
        WindowContainerTransaction wct = new WindowContainerTransaction();
        for (int i = 0; i < mTasks.size(); i++) {
            RunningTaskInfo taskInfo = mTasks.valueAt(i).getTaskInfo();
            if (taskInfo.displayId == displayId
                    && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
                    && taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD) {
                ProtoLog.d(WM_SHELL_DESKTOP_MODE,
                        "clearing windowing mode for token=%s taskInfo=%s", taskInfo.token,
                        taskInfo);
                wct.setWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED);
            }
        }
        return wct;
    }

    private void logSizeCompatRestartButtonEventReported(@NonNull TaskAppearedInfo info,
            int event) {
        ActivityInfo topActivityInfo = info.getTaskInfo().topActivityInfo;
+40 −12
Original line number Diff line number Diff line
@@ -16,8 +16,10 @@

package com.android.wm.shell.desktopmode;

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;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -151,21 +153,20 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll

        int displayId = mContext.getDisplayId();

        ArrayList<RunningTaskInfo> runningTasks = mShellTaskOrganizer.getRunningTasks(displayId);

        WindowContainerTransaction wct = new WindowContainerTransaction();
        // Reset freeform windowing mode that is set per task level (tasks should inherit
        // container value)
        wct.merge(mShellTaskOrganizer.prepareClearFreeformForStandardTasks(displayId),
                true /* transfer */);
        // Reset freeform windowing mode that is set per task level so tasks inherit it
        clearFreeformForStandardTasks(runningTasks, wct);
        int targetWindowingMode;
        if (active) {
            targetWindowingMode = WINDOWING_MODE_FREEFORM;
        } else {
            targetWindowingMode = WINDOWING_MODE_FULLSCREEN;
            // Clear any resized bounds
            wct.merge(mShellTaskOrganizer.prepareClearBoundsForStandardTasks(displayId),
                    true /* transfer */);
            clearBoundsForStandardTasks(runningTasks, wct);
        }
        prepareWindowingModeChange(wct, displayId, targetWindowingMode);
        setDisplayAreaWindowingMode(displayId, targetWindowingMode, wct);
        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
            mTransitions.startTransition(TRANSIT_CHANGE, wct, null);
        } else {
@@ -173,17 +174,44 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll
        }
    }

    private void prepareWindowingModeChange(WindowContainerTransaction wct,
            int displayId, @WindowConfiguration.WindowingMode int windowingMode) {
        DisplayAreaInfo displayAreaInfo = mRootTaskDisplayAreaOrganizer
                .getDisplayAreaInfo(displayId);
    private WindowContainerTransaction clearBoundsForStandardTasks(
            ArrayList<RunningTaskInfo> runningTasks, WindowContainerTransaction wct) {
        ProtoLog.v(WM_SHELL_DESKTOP_MODE, "prepareClearBoundsForTasks");
        for (RunningTaskInfo taskInfo : runningTasks) {
            if (taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD) {
                ProtoLog.v(WM_SHELL_DESKTOP_MODE, "clearing bounds for token=%s taskInfo=%s",
                        taskInfo.token, taskInfo);
                wct.setBounds(taskInfo.token, null);
            }
        }
        return wct;
    }

    private void clearFreeformForStandardTasks(ArrayList<RunningTaskInfo> runningTasks,
            WindowContainerTransaction wct) {
        ProtoLog.v(WM_SHELL_DESKTOP_MODE, "prepareClearFreeformForTasks");
        for (RunningTaskInfo taskInfo : runningTasks) {
            if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
                    && taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD) {
                ProtoLog.v(WM_SHELL_DESKTOP_MODE,
                        "clearing windowing mode for token=%s taskInfo=%s", taskInfo.token,
                        taskInfo);
                wct.setWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED);
            }
        }
    }

    private void setDisplayAreaWindowingMode(int displayId,
            @WindowConfiguration.WindowingMode int windowingMode, WindowContainerTransaction wct) {
        DisplayAreaInfo displayAreaInfo = mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(
                displayId);
        if (displayAreaInfo == null) {
            ProtoLog.e(WM_SHELL_DESKTOP_MODE,
                    "unable to update windowing mode for display %d display not found", displayId);
            return;
        }

        ProtoLog.d(WM_SHELL_DESKTOP_MODE,
        ProtoLog.v(WM_SHELL_DESKTOP_MODE,
                "setWindowingMode: displayId=%d current wmMode=%d new wmMode=%d", displayId,
                displayAreaInfo.configuration.windowConfiguration.getWindowingMode(),
                windowingMode);
+0 −130
Original line number Diff line number Diff line
@@ -16,13 +16,9 @@

package com.android.wm.shell;

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_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -34,8 +30,6 @@ import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIO

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
@@ -44,11 +38,9 @@ import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.ActivityManager.RunningTaskInfo;
import android.app.TaskInfo;
import android.app.WindowConfiguration;
import android.content.LocusId;
import android.content.pm.ParceledListSlice;
import android.os.Binder;
@@ -61,8 +53,6 @@ import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
import android.window.TaskAppearedInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransaction.Change;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -638,130 +628,10 @@ public class ShellTaskOrganizerTests extends ShellTestCase {
        verify(mTaskOrganizerController).restartTaskTopActivityProcessIfVisible(task1.token);
    }

    @Test
    public void testPrepareClearBoundsForStandardTasks() {
        MockToken token1 = new MockToken();
        RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_UNDEFINED, token1);
        mOrganizer.onTaskAppeared(task1, null);

        MockToken token2 = new MockToken();
        RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_UNDEFINED, token2);
        mOrganizer.onTaskAppeared(task2, null);

        MockToken otherDisplayToken = new MockToken();
        RunningTaskInfo otherDisplayTask = createTaskInfo(3, WINDOWING_MODE_UNDEFINED,
                otherDisplayToken);
        otherDisplayTask.displayId = 2;
        mOrganizer.onTaskAppeared(otherDisplayTask, null);

        WindowContainerTransaction wct = mOrganizer.prepareClearBoundsForStandardTasks(1);

        assertEquals(wct.getChanges().size(), 2);
        Change boundsChange1 = wct.getChanges().get(token1.binder());
        assertNotNull(boundsChange1);
        assertNotEquals(
                (boundsChange1.getWindowSetMask() & WindowConfiguration.WINDOW_CONFIG_BOUNDS), 0);
        assertTrue(boundsChange1.getConfiguration().windowConfiguration.getBounds().isEmpty());

        Change boundsChange2 = wct.getChanges().get(token2.binder());
        assertNotNull(boundsChange2);
        assertNotEquals(
                (boundsChange2.getWindowSetMask() & WindowConfiguration.WINDOW_CONFIG_BOUNDS), 0);
        assertTrue(boundsChange2.getConfiguration().windowConfiguration.getBounds().isEmpty());
    }

    @Test
    public void testPrepareClearBoundsForStandardTasks_onlyClearActivityTypeStandard() {
        MockToken token1 = new MockToken();
        RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_UNDEFINED, token1);
        mOrganizer.onTaskAppeared(task1, null);

        MockToken token2 = new MockToken();
        RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_UNDEFINED, token2);
        task2.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_HOME);
        mOrganizer.onTaskAppeared(task2, null);

        WindowContainerTransaction wct = mOrganizer.prepareClearBoundsForStandardTasks(1);

        // Only clear bounds for task1
        assertEquals(1, wct.getChanges().size());
        assertNotNull(wct.getChanges().get(token1.binder()));
    }

    @Test
    public void testPrepareClearFreeformForStandardTasks() {
        MockToken token1 = new MockToken();
        RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_FREEFORM, token1);
        mOrganizer.onTaskAppeared(task1, null);

        MockToken token2 = new MockToken();
        RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_MULTI_WINDOW, token2);
        mOrganizer.onTaskAppeared(task2, null);

        MockToken otherDisplayToken = new MockToken();
        RunningTaskInfo otherDisplayTask = createTaskInfo(3, WINDOWING_MODE_FREEFORM,
                otherDisplayToken);
        otherDisplayTask.displayId = 2;
        mOrganizer.onTaskAppeared(otherDisplayTask, null);

        WindowContainerTransaction wct = mOrganizer.prepareClearFreeformForStandardTasks(1);

        // Only task with freeform windowing mode and the right display should be updated
        assertEquals(wct.getChanges().size(), 1);
        Change wmModeChange1 = wct.getChanges().get(token1.binder());
        assertNotNull(wmModeChange1);
        assertEquals(wmModeChange1.getWindowingMode(), WINDOWING_MODE_UNDEFINED);
    }

    @Test
    public void testPrepareClearFreeformForStandardTasks_onlyClearActivityTypeStandard() {
        MockToken token1 = new MockToken();
        RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_FREEFORM, token1);
        mOrganizer.onTaskAppeared(task1, null);

        MockToken token2 = new MockToken();
        RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_FREEFORM, token2);
        task2.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_HOME);
        mOrganizer.onTaskAppeared(task2, null);

        WindowContainerTransaction wct = mOrganizer.prepareClearFreeformForStandardTasks(1);

        // Only clear freeform for task1
        assertEquals(1, wct.getChanges().size());
        assertNotNull(wct.getChanges().get(token1.binder()));
    }

    private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
        RunningTaskInfo taskInfo = new RunningTaskInfo();
        taskInfo.taskId = taskId;
        taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
        return taskInfo;
    }

    private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode, MockToken token) {
        RunningTaskInfo taskInfo = createTaskInfo(taskId, windowingMode);
        taskInfo.displayId = 1;
        taskInfo.token = token.token();
        taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD);
        return taskInfo;
    }

    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;
        }

        IBinder binder() {
            return mBinder;
        }
    }
}
+148 −104

File changed.

Preview size limit exceeded, changes collapsed.