Refactor task listeners mapping in ShellTaskOrganiser

Stop using windowing modes as keys for task listerners mapping to allow adding multiple listeners for one windowing mode.

Fix: 170209272
Test: go/wm-smoke
Change-Id: I31c20a00f8747a8510a5fab9e54efa63173aab6a
This commit is contained in:
Mariia Sandrikova
2020-10-07 23:10:18 +01:00
parent 53d614ccf1
commit fe89198905
5 changed files with 98 additions and 47 deletions

View File

@@ -1,6 +1,12 @@
{
"version": "1.0.0",
"messages": {
"-1823823103": {
"message": "Add listener for types=%s listener=%s",
"level": "VERBOSE",
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
},
"-1534364071": {
"message": "onTransitionReady %s: %s",
"level": "VERBOSE",
@@ -37,12 +43,6 @@
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
},
"-242812822": {
"message": "Add listener for modes=%s listener=%s",
"level": "VERBOSE",
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
},
"-191422040": {
"message": "Transition animations finished, notifying core %s",
"level": "VERBOSE",

View File

@@ -16,9 +16,17 @@
package com.android.wm.shell;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import android.annotation.IntDef;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.WindowConfiguration.WindowingMode;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
@@ -33,7 +41,6 @@ import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.util.ArrayList;
import java.util.Arrays;
/**
@@ -42,6 +49,23 @@ import java.util.Arrays;
*/
public class ShellTaskOrganizer extends TaskOrganizer {
// Intentionally using negative numbers here so the positive numbers can be used
// for task id specific listeners that will be added later.
public static final int TASK_LISTENER_TYPE_UNDEFINED = -1;
public static final int TASK_LISTENER_TYPE_FULLSCREEN = -2;
public static final int TASK_LISTENER_TYPE_MULTI_WINDOW = -3;
public static final int TASK_LISTENER_TYPE_PIP = -4;
public static final int TASK_LISTENER_TYPE_SPLIT_SCREEN = -5;
@IntDef(prefix = {"TASK_LISTENER_TYPE_"}, value = {
TASK_LISTENER_TYPE_UNDEFINED,
TASK_LISTENER_TYPE_FULLSCREEN,
TASK_LISTENER_TYPE_MULTI_WINDOW,
TASK_LISTENER_TYPE_PIP,
TASK_LISTENER_TYPE_SPLIT_SCREEN,
})
public @interface TaskListenerType {}
private static final String TAG = "ShellTaskOrganizer";
/**
@@ -54,7 +78,7 @@ public class ShellTaskOrganizer extends TaskOrganizer {
default void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {}
}
private final SparseArray<TaskListener> mListenerByWindowingMode = new SparseArray<>();
private final SparseArray<TaskListener> mTaskListenersByType = 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)
@@ -73,29 +97,29 @@ public class ShellTaskOrganizer extends TaskOrganizer {
SyncTransactionQueue syncQueue, TransactionPool transactionPool,
ShellExecutor mainExecutor, ShellExecutor animExecutor) {
super(taskOrganizerController);
addListener(new FullscreenTaskListener(syncQueue), WINDOWING_MODE_FULLSCREEN);
addListener(new FullscreenTaskListener(syncQueue), TASK_LISTENER_TYPE_FULLSCREEN);
mTransitions = new Transitions(this, transactionPool, mainExecutor, animExecutor);
if (Transitions.ENABLE_SHELL_TRANSITIONS) registerTransitionPlayer(mTransitions);
}
/**
* Adds a listener for tasks in a specific windowing mode.
* Adds a listener for tasks with given types.
*/
public void addListener(TaskListener listener, int... windowingModes) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Add listener for modes=%s listener=%s",
Arrays.toString(windowingModes), listener);
for (int winMode : windowingModes) {
if (mListenerByWindowingMode.get(winMode) != null) {
throw new IllegalArgumentException("Listener for winMode=" + winMode
public void addListener(TaskListener listener, @TaskListenerType int... taskListenerTypes) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Add listener for types=%s listener=%s",
Arrays.toString(taskListenerTypes), listener);
for (int listenerType : taskListenerTypes) {
if (mTaskListenersByType.get(listenerType) != null) {
throw new IllegalArgumentException("Listener for listenerType=" + listenerType
+ " already exists");
}
mListenerByWindowingMode.put(winMode, listener);
mTaskListenersByType.put(listenerType, listener);
// Notify the listener of all existing tasks in that windowing mode
// Notify the listener of all existing tasks with the given type.
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) {
final @TaskListenerType int taskListenerType = getTaskListenerType(data.first);
if (taskListenerType == listenerType) {
listener.onTaskAppeared(data.first, data.second);
}
}
@@ -107,12 +131,12 @@ public class ShellTaskOrganizer extends TaskOrganizer {
*/
public void removeListener(TaskListener listener) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Remove listener=%s", listener);
final int index = mListenerByWindowingMode.indexOfValue(listener);
final int index = mTaskListenersByType.indexOfValue(listener);
if (index == -1) {
Log.w(TAG, "No registered listener found");
return;
}
mListenerByWindowingMode.removeAt(index);
mTaskListenersByType.removeAt(index);
}
@Override
@@ -120,7 +144,7 @@ public class ShellTaskOrganizer extends TaskOrganizer {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task appeared taskId=%d",
taskInfo.taskId);
mTasks.put(taskInfo.taskId, new Pair<>(taskInfo, leash));
final TaskListener listener = mListenerByWindowingMode.get(getWindowingMode(taskInfo));
final TaskListener listener = mTaskListenersByType.get(getTaskListenerType(taskInfo));
if (listener != null) {
listener.onTaskAppeared(taskInfo, leash);
}
@@ -131,23 +155,23 @@ public class ShellTaskOrganizer extends TaskOrganizer {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task info changed taskId=%d",
taskInfo.taskId);
final Pair<RunningTaskInfo, SurfaceControl> data = mTasks.get(taskInfo.taskId);
final int winMode = getWindowingMode(taskInfo);
final int prevWinMode = getWindowingMode(data.first);
final @TaskListenerType int listenerType = getTaskListenerType(taskInfo);
final @TaskListenerType int prevListenerType = getTaskListenerType(data.first);
mTasks.put(taskInfo.taskId, new Pair<>(taskInfo, data.second));
if (prevWinMode != -1 && prevWinMode != winMode) {
// TODO: We currently send vanished/appeared as the task moves between win modes, but
if (prevListenerType != listenerType) {
// TODO: We currently send vanished/appeared as the task moves between types, but
// we should consider adding a different mode-changed callback
TaskListener listener = mListenerByWindowingMode.get(prevWinMode);
TaskListener listener = mTaskListenersByType.get(prevListenerType);
if (listener != null) {
listener.onTaskVanished(taskInfo);
}
listener = mListenerByWindowingMode.get(winMode);
listener = mTaskListenersByType.get(listenerType);
if (listener != null) {
SurfaceControl leash = data.second;
listener.onTaskAppeared(taskInfo, leash);
}
} else {
final TaskListener listener = mListenerByWindowingMode.get(winMode);
final TaskListener listener = mTaskListenersByType.get(listenerType);
if (listener != null) {
listener.onTaskInfoChanged(taskInfo);
}
@@ -158,7 +182,7 @@ public class ShellTaskOrganizer extends TaskOrganizer {
public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task root back pressed taskId=%d",
taskInfo.taskId);
final TaskListener listener = mListenerByWindowingMode.get(getWindowingMode(taskInfo));
final TaskListener listener = mTaskListenersByType.get(getTaskListenerType(taskInfo));
if (listener != null) {
listener.onBackPressedOnTaskRoot(taskInfo);
}
@@ -168,15 +192,38 @@ public class ShellTaskOrganizer extends TaskOrganizer {
public void onTaskVanished(RunningTaskInfo taskInfo) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task vanished taskId=%d",
taskInfo.taskId);
final int prevWinMode = getWindowingMode(mTasks.get(taskInfo.taskId).first);
final @TaskListenerType int prevListenerType =
getTaskListenerType(mTasks.get(taskInfo.taskId).first);
mTasks.remove(taskInfo.taskId);
final TaskListener listener = mListenerByWindowingMode.get(prevWinMode);
final TaskListener listener = mTaskListenersByType.get(prevListenerType);
if (listener != null) {
listener.onTaskVanished(taskInfo);
}
}
private int getWindowingMode(RunningTaskInfo taskInfo) {
@TaskListenerType
private static int getTaskListenerType(RunningTaskInfo runningTaskInfo) {
// Right now it's N:1 mapping but in the future different task listerners
// may be triggered by one windowing mode depending on task parameters.
switch (getWindowingMode(runningTaskInfo)) {
case WINDOWING_MODE_FULLSCREEN:
return TASK_LISTENER_TYPE_FULLSCREEN;
case WINDOWING_MODE_MULTI_WINDOW:
return TASK_LISTENER_TYPE_MULTI_WINDOW;
case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
return TASK_LISTENER_TYPE_SPLIT_SCREEN;
case WINDOWING_MODE_PINNED:
return TASK_LISTENER_TYPE_PIP;
case WINDOWING_MODE_FREEFORM:
case WINDOWING_MODE_UNDEFINED:
default:
return TASK_LISTENER_TYPE_UNDEFINED;
}
}
@WindowingMode
private static int getWindowingMode(RunningTaskInfo taskInfo) {
return taskInfo.configuration.windowConfiguration.getWindowingMode();
}
}

View File

@@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
@@ -282,7 +283,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
if (!PipUtils.hasSystemFeature(context)) {
Log.w(TAG, "Device not support PIP feature");
} else {
mTaskOrganizer.addListener(this, WINDOWING_MODE_PINNED);
mTaskOrganizer.addListener(this, TASK_LISTENER_TYPE_PIP);
displayController.addDisplayWindowListener(this);
}
}

View File

@@ -23,8 +23,9 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_SPLIT_SCREEN;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.WindowConfiguration;
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.Log;
@@ -56,17 +57,16 @@ class SplitScreenTaskOrganizer implements ShellTaskOrganizer.TaskListener {
ShellTaskOrganizer shellTaskOrganizer) {
mSplitScreenController = splitScreenController;
mTaskOrganizer = shellTaskOrganizer;
mTaskOrganizer.addListener(this, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
mTaskOrganizer.addListener(this, TASK_LISTENER_TYPE_SPLIT_SCREEN);
}
void init() throws RemoteException {
synchronized (this) {
try {
mPrimary = mTaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY,
WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
mSecondary = mTaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY,
WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
} catch (Exception e) {
// teardown to prevent callbacks
mTaskOrganizer.removeListener(this);

View File

@@ -19,6 +19,9 @@ package com.android.wm.shell;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_MULTI_WINDOW;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
@@ -102,10 +105,10 @@ public class ShellTaskOrganizerTests {
}
@Test
public void testOneListenerPerMode() {
mOrganizer.addListener(new TrackingTaskListener(), WINDOWING_MODE_MULTI_WINDOW);
public void testOneListenerPerType() {
mOrganizer.addListener(new TrackingTaskListener(), TASK_LISTENER_TYPE_MULTI_WINDOW);
try {
mOrganizer.addListener(new TrackingTaskListener(), WINDOWING_MODE_MULTI_WINDOW);
mOrganizer.addListener(new TrackingTaskListener(), TASK_LISTENER_TYPE_MULTI_WINDOW);
fail("Expected exception due to already registered listener");
} catch (Exception e) {
// Expected failure
@@ -116,7 +119,7 @@ public class ShellTaskOrganizerTests {
public void testAppearedVanished() {
RunningTaskInfo taskInfo = createTaskInfo(WINDOWING_MODE_MULTI_WINDOW);
TrackingTaskListener listener = new TrackingTaskListener();
mOrganizer.addListener(listener, WINDOWING_MODE_MULTI_WINDOW);
mOrganizer.addListener(listener, TASK_LISTENER_TYPE_MULTI_WINDOW);
mOrganizer.onTaskAppeared(taskInfo, null);
assertTrue(listener.appeared.contains(taskInfo));
@@ -130,7 +133,7 @@ public class ShellTaskOrganizerTests {
mOrganizer.onTaskAppeared(taskInfo, null);
TrackingTaskListener listener = new TrackingTaskListener();
mOrganizer.addListener(listener, WINDOWING_MODE_MULTI_WINDOW);
mOrganizer.addListener(listener, TASK_LISTENER_TYPE_MULTI_WINDOW);
assertTrue(listener.appeared.contains(taskInfo));
}
@@ -139,8 +142,8 @@ public class ShellTaskOrganizerTests {
RunningTaskInfo taskInfo = createTaskInfo(WINDOWING_MODE_MULTI_WINDOW);
TrackingTaskListener mwListener = new TrackingTaskListener();
TrackingTaskListener pipListener = new TrackingTaskListener();
mOrganizer.addListener(mwListener, WINDOWING_MODE_MULTI_WINDOW);
mOrganizer.addListener(pipListener, WINDOWING_MODE_PINNED);
mOrganizer.addListener(mwListener, TASK_LISTENER_TYPE_MULTI_WINDOW);
mOrganizer.addListener(pipListener, TASK_LISTENER_TYPE_PIP);
mOrganizer.onTaskAppeared(taskInfo, null);
assertTrue(mwListener.appeared.contains(taskInfo));
assertTrue(pipListener.appeared.isEmpty());