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

Commit 4421f288 authored by Winson Chung's avatar Winson Chung
Browse files

Add mechanism to register single task organizer

- Create a single task organizer in SysUI which registers as an organizer
  for multiple windowing modes internally in TaskOrgController.

Bug: 161980327
Test: atest WindowOrganizerTests
Test: atest SplitScreenTests
Test: atest PinnedStackTests
Test: atest ShellTaskOrganizerTests
Change-Id: Ic9dfbd6bcd75d9317e5a3aeb695afdff7e869d35
parent 18702a54
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -5574,7 +5574,7 @@ package android.window {
    method @BinderThread public void onTaskAppeared(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.view.SurfaceControl);
    method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo);
    method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo);
    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void registerOrganizer(int);
    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void registerOrganizer();
    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setInterceptBackPressedOnTaskRoot(boolean);
    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static void setLaunchRoot(int, @NonNull android.window.WindowContainerToken);
    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void unregisterOrganizer();
+2 −4
Original line number Diff line number Diff line
@@ -25,11 +25,9 @@ import android.window.WindowContainerTransaction;
interface ITaskOrganizerController {

    /**
     * Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
     * If there was already a TaskOrganizer for this windowing mode it will be evicted
     * and receive taskVanished callbacks in the process.
     * Register a TaskOrganizer to manage all the tasks with supported windowing modes.
     */
    void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode);
    void registerTaskOrganizer(ITaskOrganizer organizer);

    /**
     * Unregisters a previously registered task organizer.
+3 −5
Original line number Diff line number Diff line
@@ -36,14 +36,12 @@ import java.util.List;
public class TaskOrganizer extends WindowOrganizer {

    /**
     * Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
     * If there was already a TaskOrganizer for this windowing mode it will be evicted
     * and receive taskVanished callbacks in the process.
     * Register a TaskOrganizer to manage tasks as they enter a supported windowing mode.
     */
    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
    public final void registerOrganizer(int windowingMode) {
    public final void registerOrganizer() {
        try {
            getController().registerTaskOrganizer(mInterface, windowingMode);
            getController().registerTaskOrganizer(mInterface);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
+1 −1
Original line number Diff line number Diff line
@@ -73,7 +73,7 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder {
        // TODO(wm-shell): This currently prevents other organizers from controlling MULT_WINDOW
        // windowing mode tasks. Plan is to migrate this to a wm-shell front-end when that
        // infrastructure is ready.
        mTaskOrganizer.registerOrganizer(WINDOWING_MODE_MULTI_WINDOW);
        // mTaskOrganizer.registerOrganizer();
        mTaskOrganizer.setInterceptBackPressedOnTaskRoot(true);

        return super.onInitialize();
+161 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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;

import android.app.ActivityManager.RunningTaskInfo;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.Surface;
import android.view.SurfaceControl;
import android.window.TaskOrganizer;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Unified task organizer for all components in the shell.
 */
public class ShellTaskOrganizer extends TaskOrganizer {

    private static final String TAG = "ShellTaskOrganizer";

    /**
     * Callbacks for when the tasks change in the system.
     */
    public interface TaskListener {
        default void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {}
        default void onTaskInfoChanged(RunningTaskInfo taskInfo) {}
        default void onTaskVanished(RunningTaskInfo taskInfo) {}
        default void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {}
    }

    private final SparseArray<ArrayList<TaskListener>> mListenersByWindowingMode =
            new SparseArray<>();

    // Keeps track of all the tasks reported to this organizer (changes in windowing mode will
    // require us to report to both old and new listeners)
    private final SparseArray<Pair<RunningTaskInfo, SurfaceControl>> mTasks = new SparseArray<>();

    /**
     * Adds a listener for tasks in a specific windowing mode.
     */
    public void addListener(TaskListener listener, int... windowingModes) {
        for (int winMode : windowingModes) {
            ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(winMode);
            if (listeners == null) {
                listeners = new ArrayList<>();
                mListenersByWindowingMode.put(winMode, listeners);
            }
            if (listeners.contains(listener)) {
                Log.w(TAG, "Listener already exists");
                return;
            }
            listeners.add(listener);

            // Notify the listener of all existing tasks in that windowing mode
            for (int i = mTasks.size() - 1; i >= 0; i--) {
                Pair<RunningTaskInfo, SurfaceControl> data = mTasks.valueAt(i);
                int taskWinMode = data.first.configuration.windowConfiguration.getWindowingMode();
                if (taskWinMode == winMode) {
                    listener.onTaskAppeared(data.first, data.second);
                }
            }
        }
    }

    /**
     * Removes a registered listener.
     */
    public void removeListener(TaskListener listener) {
        for (int i = 0; i < mListenersByWindowingMode.size(); i++) {
            mListenersByWindowingMode.valueAt(i).remove(listener);
        }
    }

    @Override
    public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
        mTasks.put(taskInfo.taskId, new Pair<>(taskInfo, leash));
        ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(
                getWindowingMode(taskInfo));
        if (listeners != null) {
            for (int i = listeners.size() - 1; i >= 0; i--) {
                listeners.get(i).onTaskAppeared(taskInfo, leash);
            }
        }
    }

    @Override
    public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
        Pair<RunningTaskInfo, SurfaceControl> data = mTasks.get(taskInfo.taskId);
        int winMode = getWindowingMode(taskInfo);
        int prevWinMode = getWindowingMode(data.first);
        if (prevWinMode != -1 && prevWinMode != winMode) {
            // TODO: We currently send vanished/appeared as the task moves between win modes, but
            //       we should consider adding a different mode-changed callback
            ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(prevWinMode);
            if (listeners != null) {
                for (int i = listeners.size() - 1; i >= 0; i--) {
                    listeners.get(i).onTaskVanished(taskInfo);
                }
            }
            listeners = mListenersByWindowingMode.get(winMode);
            if (listeners != null) {
                SurfaceControl leash = data.second;
                for (int i = listeners.size() - 1; i >= 0; i--) {
                    listeners.get(i).onTaskAppeared(taskInfo, leash);
                }
            }
        } else {
            ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(winMode);
            if (listeners != null) {
                for (int i = listeners.size() - 1; i >= 0; i--) {
                    listeners.get(i).onTaskInfoChanged(taskInfo);
                }
            }
        }
    }

    @Override
    public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
        ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(
                getWindowingMode(taskInfo));
        if (listeners != null) {
            for (int i = listeners.size() - 1; i >= 0; i--) {
                listeners.get(i).onBackPressedOnTaskRoot(taskInfo);
            }
        }
    }

    @Override
    public void onTaskVanished(RunningTaskInfo taskInfo) {
        int prevWinMode = getWindowingMode(mTasks.get(taskInfo.taskId).first);
        mTasks.remove(taskInfo.taskId);
        ArrayList<TaskListener> listeners = mListenersByWindowingMode.get(prevWinMode);
        if (listeners != null) {
            for (int i = listeners.size() - 1; i >= 0; i--) {
                listeners.get(i).onTaskVanished(taskInfo);
            }
        }
    }

    private int getWindowingMode(RunningTaskInfo taskInfo) {
        return taskInfo.configuration.windowConfiguration.getWindowingMode();
    }
}
Loading