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

Commit 7d4b51d2 authored by Winson Chung's avatar Winson Chung Committed by Android (Google) Code Review
Browse files

Merge "Add mechanism to register single task organizer"

parents 7dafd21f 4421f288
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -5577,7 +5577,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