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

Commit 7112c035 authored by Gustav Sennton's avatar Gustav Sennton
Browse files

Mark minimized Recents tasks in GroupedRecentTaskInfo.java and Task.java

With this CL we mark Recent Desktop tasks so that SystemUI / Launcher
can know which tasks are minimized.

Note: when we're in desktop mode it is enough to know whether a desktop
task is visible to know whether it is minimized. However, when outside
desktop mode (e.g. in Overview) all desktop tasks are marked invisible
so we need to have a separate field to know whether a task is minimized.

Bug: 333013317
Flag: com.android.window.flags.enable_desktop_windowing_mode
Test: manual: ensured minimized desktop tasks are not shown in Overview

Change-Id: I9011676234762a9b81d0df84c300fea05f6df442
parent e84fdcef
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -65,9 +65,11 @@ import com.android.wm.shell.util.SplitBounds;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.function.Consumer;

@@ -394,6 +396,7 @@ public class RecentTasksController implements TaskStackListenerCallback,
        }

        ArrayList<ActivityManager.RecentTaskInfo> freeformTasks = new ArrayList<>();
        Set<Integer> minimizedFreeformTasks = new HashSet<>();

        int mostRecentFreeformTaskIndex = Integer.MAX_VALUE;

@@ -414,6 +417,9 @@ public class RecentTasksController implements TaskStackListenerCallback,
                    mostRecentFreeformTaskIndex = recentTasks.size();
                }
                freeformTasks.add(taskInfo);
                if (mDesktopModeTaskRepository.get().isMinimizedTask(taskInfo.taskId)) {
                    minimizedFreeformTasks.add(taskInfo.taskId);
                }
                continue;
            }

@@ -431,8 +437,10 @@ public class RecentTasksController implements TaskStackListenerCallback,

        // Add a special entry for freeform tasks
        if (!freeformTasks.isEmpty()) {
            recentTasks.add(mostRecentFreeformTaskIndex, GroupedRecentTaskInfo.forFreeformTasks(
                    freeformTasks.toArray(new ActivityManager.RecentTaskInfo[0])));
            recentTasks.add(mostRecentFreeformTaskIndex,
                    GroupedRecentTaskInfo.forFreeformTasks(
                            freeformTasks.toArray(new ActivityManager.RecentTaskInfo[0]),
                            minimizedFreeformTasks));
        }

        return recentTasks;
+40 −6
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import androidx.annotation.Nullable;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * Simple container for recent tasks.  May contain either a single or pair of tasks.
@@ -50,6 +51,9 @@ public class GroupedRecentTaskInfo implements Parcelable {
    private final SplitBounds mSplitBounds;
    @GroupType
    private final int mType;
    // TODO(b/348332802): move isMinimized inside each Task object instead once we have a
    //  replacement for RecentTaskInfo
    private final int[] mMinimizedTaskIds;

    /**
     * Create new for a single task
@@ -57,7 +61,7 @@ public class GroupedRecentTaskInfo implements Parcelable {
    public static GroupedRecentTaskInfo forSingleTask(
            @NonNull ActivityManager.RecentTaskInfo task) {
        return new GroupedRecentTaskInfo(new ActivityManager.RecentTaskInfo[]{task}, null,
                TYPE_SINGLE);
                TYPE_SINGLE, null /* minimizedFreeformTasks */);
    }

    /**
@@ -66,28 +70,51 @@ public class GroupedRecentTaskInfo implements Parcelable {
    public static GroupedRecentTaskInfo forSplitTasks(@NonNull ActivityManager.RecentTaskInfo task1,
            @NonNull ActivityManager.RecentTaskInfo task2, @Nullable SplitBounds splitBounds) {
        return new GroupedRecentTaskInfo(new ActivityManager.RecentTaskInfo[]{task1, task2},
                splitBounds, TYPE_SPLIT);
                splitBounds, TYPE_SPLIT, null /* minimizedFreeformTasks */);
    }

    /**
     * Create new for a group of freeform tasks
     */
    public static GroupedRecentTaskInfo forFreeformTasks(
            @NonNull ActivityManager.RecentTaskInfo... tasks) {
        return new GroupedRecentTaskInfo(tasks, null, TYPE_FREEFORM);
    }

    private GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo[] tasks,
            @Nullable SplitBounds splitBounds, @GroupType int type) {
            @NonNull ActivityManager.RecentTaskInfo[] tasks,
            @NonNull Set<Integer> minimizedFreeformTasks) {
        return new GroupedRecentTaskInfo(
                tasks,
                null /* splitBounds */,
                TYPE_FREEFORM,
                minimizedFreeformTasks.stream().mapToInt(i -> i).toArray());
    }

    private GroupedRecentTaskInfo(
            @NonNull ActivityManager.RecentTaskInfo[] tasks,
            @Nullable SplitBounds splitBounds,
            @GroupType int type,
            @Nullable int[] minimizedFreeformTaskIds) {
        mTasks = tasks;
        mSplitBounds = splitBounds;
        mType = type;
        mMinimizedTaskIds = minimizedFreeformTaskIds;
        ensureAllMinimizedIdsPresent(tasks, minimizedFreeformTaskIds);
    }

    private static void ensureAllMinimizedIdsPresent(
            @NonNull ActivityManager.RecentTaskInfo[] tasks,
            @Nullable int[] minimizedFreeformTaskIds) {
        if (minimizedFreeformTaskIds == null) {
            return;
        }
        if (!Arrays.stream(minimizedFreeformTaskIds).allMatch(
                taskId -> Arrays.stream(tasks).anyMatch(task -> task.taskId == taskId))) {
            throw new IllegalArgumentException("Minimized task IDs contain non-existent Task ID.");
        }
    }

    GroupedRecentTaskInfo(Parcel parcel) {
        mTasks = parcel.createTypedArray(ActivityManager.RecentTaskInfo.CREATOR);
        mSplitBounds = parcel.readTypedObject(SplitBounds.CREATOR);
        mType = parcel.readInt();
        mMinimizedTaskIds = parcel.createIntArray();
    }

    /**
@@ -135,6 +162,10 @@ public class GroupedRecentTaskInfo implements Parcelable {
        return mType;
    }

    public int[] getMinimizedTaskIds() {
        return mMinimizedTaskIds;
    }

    @Override
    public String toString() {
        StringBuilder taskString = new StringBuilder();
@@ -161,6 +192,8 @@ public class GroupedRecentTaskInfo implements Parcelable {
                taskString.append("TYPE_FREEFORM");
                break;
        }
        taskString.append(", Minimized Task IDs: ");
        taskString.append(Arrays.toString(mMinimizedTaskIds));
        return taskString.toString();
    }

@@ -181,6 +214,7 @@ public class GroupedRecentTaskInfo implements Parcelable {
        parcel.writeTypedArray(mTasks, flags);
        parcel.writeTypedObject(mSplitBounds, flags);
        parcel.writeInt(mType);
        parcel.writeIntArray(mMinimizedTaskIds);
    }

    @Override
+39 −9
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.wm.shell.recents

import android.app.ActivityManager
import android.app.ActivityManager.RecentTaskInfo
import android.graphics.Rect
import android.os.Parcel
import android.testing.AndroidTestingRunner
@@ -33,6 +34,7 @@ import com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_SPLIT
import com.android.wm.shell.util.SplitBounds
import com.google.common.truth.Correspondence
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertThrows
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
@@ -86,18 +88,29 @@ class GroupedRecentTaskInfoTest : ShellTestCase() {

    @Test
    fun testFreeformTasks_hasCorrectType() {
        assertThat(freeformTasksGroupInfo().type).isEqualTo(TYPE_FREEFORM)
        assertThat(freeformTasksGroupInfo(freeformTaskIds = arrayOf(1)).type)
            .isEqualTo(TYPE_FREEFORM)
    }

    @Test
    fun testSplitTasks_taskInfoList_hasThreeTasks() {
        val list = freeformTasksGroupInfo().taskInfoList
    fun testCreateFreeformTasks_hasCorrectNumberOfTasks() {
        val list = freeformTasksGroupInfo(freeformTaskIds = arrayOf(1, 2, 3)).taskInfoList
        assertThat(list).hasSize(3)
        assertThat(list[0].taskId).isEqualTo(1)
        assertThat(list[1].taskId).isEqualTo(2)
        assertThat(list[2].taskId).isEqualTo(3)
    }

    @Test
    fun testCreateFreeformTasks_nonExistentMinimizedTaskId_throwsException() {
        assertThrows(IllegalArgumentException::class.java) {
            freeformTasksGroupInfo(
                freeformTaskIds = arrayOf(1, 2, 3),
                minimizedTaskIds = arrayOf(1, 4)
            )
        }
    }

    @Test
    fun testParcelling_singleTask() {
        val recentTaskInfo = singleTaskGroupInfo()
@@ -129,7 +142,7 @@ class GroupedRecentTaskInfoTest : ShellTestCase() {

    @Test
    fun testParcelling_freeformTasks() {
        val recentTaskInfo = freeformTasksGroupInfo()
        val recentTaskInfo = freeformTasksGroupInfo(freeformTaskIds = arrayOf(1, 2, 3))
        val parcel = Parcel.obtain()
        recentTaskInfo.writeToParcel(parcel, 0)
        parcel.setDataPosition(0)
@@ -145,6 +158,21 @@ class GroupedRecentTaskInfoTest : ShellTestCase() {
            .containsExactly(1, 2, 3)
    }

    @Test
    fun testParcelling_freeformTasks_minimizedTasks() {
        val recentTaskInfo = freeformTasksGroupInfo(
            freeformTaskIds = arrayOf(1, 2, 3), minimizedTaskIds = arrayOf(2))

        val parcel = Parcel.obtain()
        recentTaskInfo.writeToParcel(parcel, 0)
        parcel.setDataPosition(0)

        // Read the object back from the parcel
        val recentTaskInfoParcel = CREATOR.createFromParcel(parcel)
        assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_FREEFORM)
        assertThat(recentTaskInfoParcel.minimizedTaskIds).isEqualTo(arrayOf(2).toIntArray())
    }

    private fun createTaskInfo(id: Int) = ActivityManager.RecentTaskInfo().apply {
        taskId = id
        token = WindowContainerToken(mock(IWindowContainerToken::class.java))
@@ -162,10 +190,12 @@ class GroupedRecentTaskInfoTest : ShellTestCase() {
        return GroupedRecentTaskInfo.forSplitTasks(task1, task2, splitBounds)
    }

    private fun freeformTasksGroupInfo(): GroupedRecentTaskInfo {
        val task1 = createTaskInfo(id = 1)
        val task2 = createTaskInfo(id = 2)
        val task3 = createTaskInfo(id = 3)
        return GroupedRecentTaskInfo.forFreeformTasks(task1, task2, task3)
    private fun freeformTasksGroupInfo(
        freeformTaskIds: Array<Int>,
        minimizedTaskIds: Array<Int> = emptyArray()
    ): GroupedRecentTaskInfo {
        return GroupedRecentTaskInfo.forFreeformTasks(
            freeformTaskIds.map { createTaskInfo(it) }.toTypedArray(),
            minimizedTaskIds.toSet())
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -249,6 +249,9 @@ public class Task {
    @ViewDebug.ExportedProperty(category="recents")
    public boolean isVisible;

    @ViewDebug.ExportedProperty(category = "recents")
    public boolean isMinimized;

    public Task() {
        // Do nothing
    }
@@ -283,6 +286,7 @@ public class Task {
        positionInParent = other.positionInParent;
        appBounds = other.appBounds;
        isVisible = other.isVisible;
        isMinimized = other.isMinimized;
    }

    /**