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

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

Track active freeform tasks

Track active freeform tasks and filter them from recent tasks in overview if
desktop mode is active.
A task is considered an active freeform task if it meets the following criteria:
- task is running
- task has been visible at least once when desktop mode was on

Bug: 244348395
Test: atest RecentTasksControllerTest
Change-Id: I10854b467615fc5bb257c1719d3887643d28fd52
parent fcc50ef1
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -876,8 +876,12 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
                    pkg = info.getTaskInfo().baseActivity.getPackageName();
                }
                Rect bounds = info.getTaskInfo().getConfiguration().windowConfiguration.getBounds();
                boolean running = info.getTaskInfo().isRunning;
                boolean visible = info.getTaskInfo().isVisible;
                boolean focused = info.getTaskInfo().isFocused;
                pw.println(innerPrefix + "#" + i + " task=" + key + " listener=" + listener
                        + " wmMode=" + windowingMode + " pkg=" + pkg + " bounds=" + bounds);
                        + " wmMode=" + windowingMode + " pkg=" + pkg + " bounds=" + bounds
                        + " running=" + running + " visible=" + visible + " focused=" + focused);
            }

            pw.println();
+2 −1
Original line number Diff line number Diff line
@@ -220,13 +220,14 @@ public abstract class WMShellModule {
            Context context,
            ShellInit shellInit,
            ShellTaskOrganizer shellTaskOrganizer,
            Optional<RecentTasksController> recentTasksController,
            WindowDecorViewModel<?> windowDecorViewModel) {
        // TODO(b/238217847): Temporarily add this check here until we can remove the dynamic
        //                    override for this controller from the base module
        ShellInit init = FreeformComponents.isFreeformEnabled(context)
                ? shellInit
                : null;
        return new FreeformTaskListener<>(init, shellTaskOrganizer,
        return new FreeformTaskListener<>(init, shellTaskOrganizer, recentTasksController,
                windowDecorViewModel);
    }

+1 −1
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ public class DesktopMode {
                    Settings.System.DESKTOP_MODE, UserHandle.USER_CURRENT);
            ProtoLog.d(WM_SHELL_DESKTOP_MODE, "isDesktopModeEnabled=%s", result);
            return result != 0;
        } catch (Settings.SettingNotFoundException e) {
        } catch (Exception e) {
            ProtoLog.e(WM_SHELL_DESKTOP_MODE, "Failed to read DESKTOP_MODE setting %s", e);
            return false;
        }
+26 −0
Original line number Diff line number Diff line
@@ -28,12 +28,15 @@ import androidx.annotation.Nullable;

import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.WindowDecorViewModel;

import java.io.PrintWriter;
import java.util.Optional;

/**
 * {@link ShellTaskOrganizer.TaskListener} for {@link
@@ -46,6 +49,7 @@ public class FreeformTaskListener<T extends AutoCloseable>
    private static final String TAG = "FreeformTaskListener";

    private final ShellTaskOrganizer mShellTaskOrganizer;
    private final Optional<RecentTasksController> mRecentTasksOptional;
    private final WindowDecorViewModel<T> mWindowDecorationViewModel;

    private final SparseArray<State<T>> mTasks = new SparseArray<>();
@@ -60,9 +64,11 @@ public class FreeformTaskListener<T extends AutoCloseable>
    public FreeformTaskListener(
            ShellInit shellInit,
            ShellTaskOrganizer shellTaskOrganizer,
            Optional<RecentTasksController> recentTasksController,
            WindowDecorViewModel<T> windowDecorationViewModel) {
        mShellTaskOrganizer = shellTaskOrganizer;
        mWindowDecorationViewModel = windowDecorationViewModel;
        mRecentTasksOptional = recentTasksController;
        if (shellInit != null) {
            shellInit.addInitCallback(this::onInit, this);
        }
@@ -83,6 +89,12 @@ public class FreeformTaskListener<T extends AutoCloseable>
                    mWindowDecorationViewModel.createWindowDecoration(taskInfo, leash, t, t);
            t.apply();
        }

        if (DesktopMode.IS_SUPPORTED && taskInfo.isVisible) {
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
                    "Adding active freeform task: #%d", taskInfo.taskId);
            mRecentTasksOptional.ifPresent(rt -> rt.addActiveFreeformTask(taskInfo.taskId));
        }
    }

    private State<T> createOrUpdateTaskState(RunningTaskInfo taskInfo, SurfaceControl leash) {
@@ -111,6 +123,12 @@ public class FreeformTaskListener<T extends AutoCloseable>
                taskInfo.taskId);
        mTasks.remove(taskInfo.taskId);

        if (DesktopMode.IS_SUPPORTED) {
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
                    "Removing active freeform task: #%d", taskInfo.taskId);
            mRecentTasksOptional.ifPresent(rt -> rt.removeActiveFreeformTask(taskInfo.taskId));
        }

        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
            // Save window decorations of closing tasks so that we can hand them over to the
            // transition system if this method happens before the transition. In case where the
@@ -131,6 +149,14 @@ public class FreeformTaskListener<T extends AutoCloseable>
        if (state.mWindowDecoration != null) {
            mWindowDecorationViewModel.onTaskInfoChanged(state.mTaskInfo, state.mWindowDecoration);
        }

        if (DesktopMode.IS_SUPPORTED) {
            if (taskInfo.isVisible) {
                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
                        "Adding active freeform task: #%d", taskInfo.taskId);
                mRecentTasksOptional.ifPresent(rt -> rt.addActiveFreeformTask(taskInfo.taskId));
            }
        }
    }

    private State<T> updateTaskInfo(RunningTaskInfo taskInfo) {
+48 −3
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellInit;
@@ -52,6 +53,7 @@ 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;

@@ -81,6 +83,15 @@ public class RecentTasksController implements TaskStackListenerCallback,
     */
    private final Map<Integer, SplitBounds> mTaskSplitBoundsMap = new HashMap<>();

    /**
     * Set of taskId's that have been launched in freeform mode.
     * This includes tasks that are currently running, visible and in freeform mode. And also
     * includes tasks that are running in the background, are no longer visible, but at some point
     * were visible to the user.
     * This is used to decide which freeform apps belong to the user's desktop.
     */
    private final HashSet<Integer> mActiveFreeformTasks = new HashSet<>();

    /**
     * Creates {@link RecentTasksController}, returns {@code null} if the feature is not
     * supported.
@@ -206,6 +217,22 @@ public class RecentTasksController implements TaskStackListenerCallback,
        notifyRecentTasksChanged();
    }

    /**
     * Mark a task with given {@code taskId} as active in freeform
     */
    public void addActiveFreeformTask(int taskId) {
        mActiveFreeformTasks.add(taskId);
        notifyRecentTasksChanged();
    }

    /**
     * Remove task with given {@code taskId} from active freeform tasks
     */
    public void removeActiveFreeformTask(int taskId) {
        mActiveFreeformTasks.remove(taskId);
        notifyRecentTasksChanged();
    }

    @VisibleForTesting
    void notifyRecentTasksChanged() {
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENT_TASKS, "Notify recent tasks changed");
@@ -273,6 +300,9 @@ public class RecentTasksController implements TaskStackListenerCallback,
            rawMapping.put(taskInfo.taskId, taskInfo);
        }

        boolean desktopModeActive = DesktopMode.isActive(mContext);
        ArrayList<ActivityManager.RecentTaskInfo> freeformTasks = new ArrayList<>();

        // Pull out the pairs as we iterate back in the list
        ArrayList<GroupedRecentTaskInfo> recentTasks = new ArrayList<>();
        for (int i = 0; i < rawList.size(); i++) {
@@ -282,16 +312,31 @@ public class RecentTasksController implements TaskStackListenerCallback,
                continue;
            }

            if (desktopModeActive && mActiveFreeformTasks.contains(taskInfo.taskId)) {
                // Freeform tasks will be added as a separate entry
                freeformTasks.add(taskInfo);
                continue;
            }

            final int pairedTaskId = mSplitTasks.get(taskInfo.taskId);
            if (pairedTaskId != INVALID_TASK_ID && rawMapping.contains(pairedTaskId)) {
            if (!desktopModeActive && pairedTaskId != INVALID_TASK_ID && rawMapping.contains(
                    pairedTaskId)) {
                final ActivityManager.RecentTaskInfo pairedTaskInfo = rawMapping.get(pairedTaskId);
                rawMapping.remove(pairedTaskId);
                recentTasks.add(new GroupedRecentTaskInfo(taskInfo, pairedTaskInfo,
                recentTasks.add(GroupedRecentTaskInfo.forSplitTasks(taskInfo, pairedTaskInfo,
                        mTaskSplitBoundsMap.get(pairedTaskId)));
            } else {
                recentTasks.add(new GroupedRecentTaskInfo(taskInfo));
                recentTasks.add(GroupedRecentTaskInfo.forSingleTask(taskInfo));
            }
        }

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

        return recentTasks;
    }

Loading