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

Commit 8a3cf44c authored by Ats Jenk's avatar Ats Jenk
Browse files

Move active task tracking to a repository

We were tracking active freeform tasks in the RecentTasksController.
This causes some issues when we want to share that information to other
controllers like DesktopModeController.
Move tracking of active tasks to a separate repository that controllers
can query and listen for updates.

Bug: 244348395
Test: atest DesktopModeTaskRepositoryTest RecentTasksControllerTest
Change-Id: I7a460020f6b2133225e292a04f29ae1dd27e964b
parent db23075a
Loading
Loading
Loading
Loading
+22 −1
Original line number Diff line number Diff line
@@ -55,6 +55,8 @@ import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
import com.android.wm.shell.compatui.CompatUIController;
import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
import com.android.wm.shell.displayareahelper.DisplayAreaHelperController;
import com.android.wm.shell.draganddrop.DragAndDropController;
@@ -477,11 +479,12 @@ public abstract class WMShellBaseModule {
            ShellInit shellInit,
            ShellCommandHandler shellCommandHandler,
            TaskStackListenerImpl taskStackListener,
            Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
            @ShellMainThread ShellExecutor mainExecutor
    ) {
        return Optional.ofNullable(
                RecentTasksController.create(context, shellInit, shellCommandHandler,
                        taskStackListener, mainExecutor));
                        taskStackListener, desktopModeTaskRepository, mainExecutor));
    }

    //
@@ -665,6 +668,24 @@ public abstract class WMShellBaseModule {
        return new ShellController(shellInit, shellCommandHandler, mainExecutor);
    }

    //
    // Desktop mode (optional feature)
    //

    @BindsOptionalOf
    @DynamicOverride
    abstract DesktopModeTaskRepository optionalDesktopModeTaskRepository();

    @WMSingleton
    @Provides
    static Optional<DesktopModeTaskRepository> providesDesktopModeTaskRepository(
            @DynamicOverride Optional<DesktopModeTaskRepository> desktopModeTaskRepository) {
        if (DesktopMode.IS_SUPPORTED) {
            return desktopModeTaskRepository;
        }
        return Optional.empty();
    }

    //
    // Misc
    //
+10 −2
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformComponents;
import com.android.wm.shell.freeform.FreeformTaskListener;
@@ -220,14 +221,14 @@ public abstract class WMShellModule {
            Context context,
            ShellInit shellInit,
            ShellTaskOrganizer shellTaskOrganizer,
            Optional<RecentTasksController> recentTasksController,
            Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
            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, recentTasksController,
        return new FreeformTaskListener<>(init, shellTaskOrganizer, desktopModeTaskRepository,
                windowDecorViewModel);
    }

@@ -610,6 +611,13 @@ public abstract class WMShellModule {
        }
    }

    @WMSingleton
    @Provides
    @DynamicOverride
    static DesktopModeTaskRepository provideDesktopModeTaskRepository() {
        return new DesktopModeTaskRepository();
    }

    //
    // Misc
    //
+89 −0
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.util.ArraySet

/**
 * Keeps track of task data related to desktop mode.
 */
class DesktopModeTaskRepository {

    /**
     * Set of task ids that are marked as active in desktop mode.
     * Active tasks in desktop mode are freeform tasks that are visible or have been visible after
     * desktop mode was activated.
     * Task gets removed from this list when it vanishes. Or when desktop mode is turned off.
     */
    private val activeTasks = ArraySet<Int>()
    private val listeners = ArraySet<Listener>()

    /**
     * Add a [Listener] to be notified of updates to the repository.
     */
    fun addListener(listener: Listener) {
        listeners.add(listener)
    }

    /**
     * Remove a previously registered [Listener]
     */
    fun removeListener(listener: Listener) {
        listeners.remove(listener)
    }

    /**
     * Mark a task with given [taskId] as active.
     */
    fun addActiveTask(taskId: Int) {
        val added = activeTasks.add(taskId)
        if (added) {
            listeners.onEach { it.onActiveTasksChanged() }
        }
    }

    /**
     * Remove task with given [taskId] from active tasks.
     */
    fun removeActiveTask(taskId: Int) {
        val removed = activeTasks.remove(taskId)
        if (removed) {
            listeners.onEach { it.onActiveTasksChanged() }
        }
    }

    /**
     * Check if a task with the given [taskId] was marked as an active task
     */
    fun isActiveTask(taskId: Int): Boolean {
        return activeTasks.contains(taskId)
    }

    /**
     * Get a set of the active tasks
     */
    fun getActiveTasks(): ArraySet<Int> {
        return ArraySet(activeTasks)
    }

    /**
     * Defines interface for classes that can listen to changes in repository state.
     */
    interface Listener {
        fun onActiveTasksChanged()
    }
}
+7 −7
Original line number Diff line number Diff line
@@ -29,8 +29,8 @@ 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.desktopmode.DesktopModeTaskRepository;
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;
@@ -49,7 +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 Optional<DesktopModeTaskRepository> mDesktopModeTaskRepository;
    private final WindowDecorViewModel<T> mWindowDecorationViewModel;

    private final SparseArray<State<T>> mTasks = new SparseArray<>();
@@ -64,11 +64,11 @@ public class FreeformTaskListener<T extends AutoCloseable>
    public FreeformTaskListener(
            ShellInit shellInit,
            ShellTaskOrganizer shellTaskOrganizer,
            Optional<RecentTasksController> recentTasksController,
            Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
            WindowDecorViewModel<T> windowDecorationViewModel) {
        mShellTaskOrganizer = shellTaskOrganizer;
        mWindowDecorationViewModel = windowDecorationViewModel;
        mRecentTasksOptional = recentTasksController;
        mDesktopModeTaskRepository = desktopModeTaskRepository;
        if (shellInit != null) {
            shellInit.addInitCallback(this::onInit, this);
        }
@@ -93,7 +93,7 @@ public class FreeformTaskListener<T extends AutoCloseable>
        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));
            mDesktopModeTaskRepository.ifPresent(it -> it.addActiveTask(taskInfo.taskId));
        }
    }

@@ -126,7 +126,7 @@ public class FreeformTaskListener<T extends AutoCloseable>
        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));
            mDesktopModeTaskRepository.ifPresent(it -> it.removeActiveTask(taskInfo.taskId));
        }

        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
@@ -154,7 +154,7 @@ public class FreeformTaskListener<T extends AutoCloseable>
            if (taskInfo.isVisible) {
                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
                        "Adding active freeform task: #%d", taskInfo.taskId);
                mRecentTasksOptional.ifPresent(rt -> rt.addActiveFreeformTask(taskInfo.taskId));
                mDesktopModeTaskRepository.ifPresent(it -> it.addActiveTask(taskInfo.taskId));
            }
        }
    }
+13 −26
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ 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.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellInit;
@@ -53,19 +54,20 @@ 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;

/**
 * Manages the recent task list from the system, caching it as necessary.
 */
public class RecentTasksController implements TaskStackListenerCallback,
        RemoteCallable<RecentTasksController> {
        RemoteCallable<RecentTasksController>, DesktopModeTaskRepository.Listener {
    private static final String TAG = RecentTasksController.class.getSimpleName();

    private final Context mContext;
    private final ShellCommandHandler mShellCommandHandler;
    private final Optional<DesktopModeTaskRepository> mDesktopModeTaskRepository;
    private final ShellExecutor mMainExecutor;
    private final TaskStackListenerImpl mTaskStackListener;
    private final RecentTasks mImpl = new RecentTasksImpl();
@@ -83,15 +85,6 @@ 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.
@@ -102,24 +95,27 @@ public class RecentTasksController implements TaskStackListenerCallback,
            ShellInit shellInit,
            ShellCommandHandler shellCommandHandler,
            TaskStackListenerImpl taskStackListener,
            Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
            @ShellMainThread ShellExecutor mainExecutor
    ) {
        if (!context.getResources().getBoolean(com.android.internal.R.bool.config_hasRecents)) {
            return null;
        }
        return new RecentTasksController(context, shellInit, shellCommandHandler, taskStackListener,
                mainExecutor);
                desktopModeTaskRepository, mainExecutor);
    }

    RecentTasksController(Context context,
            ShellInit shellInit,
            ShellCommandHandler shellCommandHandler,
            TaskStackListenerImpl taskStackListener,
            Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
            ShellExecutor mainExecutor) {
        mContext = context;
        mShellCommandHandler = shellCommandHandler;
        mIsDesktopMode = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
        mTaskStackListener = taskStackListener;
        mDesktopModeTaskRepository = desktopModeTaskRepository;
        mMainExecutor = mainExecutor;
        shellInit.addInitCallback(this::onInit, this);
    }
@@ -131,6 +127,7 @@ public class RecentTasksController implements TaskStackListenerCallback,
    private void onInit() {
        mShellCommandHandler.addDumpCallback(this::dump, this);
        mTaskStackListener.addListener(this);
        mDesktopModeTaskRepository.ifPresent(it -> it.addListener(this));
    }

    /**
@@ -217,19 +214,8 @@ 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);
    @Override
    public void onActiveTasksChanged() {
        notifyRecentTasksChanged();
    }

@@ -312,7 +298,8 @@ public class RecentTasksController implements TaskStackListenerCallback,
                continue;
            }

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