Add task organizer based task embedder
- Split TaskEmbedder into its current VirtualDisplay implementation
and an implementation that uses task org to create and manage
the task
- Use the task org embedder implementation in separate bubble task view
- Skip task org tasks from triggering task resizing
- Add task org callback for back press on task root if requested
Bug: 148977538
Test: atest CtsWindowManagerDeviceTestCases:ActivityViewTest
Test: atest WmTests:TaskOrganizerTests
Change-Id: Id422bb2547197c617f914ed7cf5085e02a1c3fb5
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 7e999c6..bda6da5 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2420,7 +2420,12 @@
return;
}
ActivityStack stack = r.getRootTask();
- if (stack != null && stack.isSingleTaskInstance()) {
+ final TaskOrganizerController taskOrgController =
+ mWindowOrganizerController.mTaskOrganizerController;
+ if (taskOrgController.handleInterceptBackPressedOnTaskRoot(stack)) {
+ // This task is handled by a task organizer that has requested the back pressed
+ // callback
+ } else if (stack != null && (stack.isSingleTaskInstance())) {
// Single-task stacks are used for activities which are presented in floating
// windows above full screen activities. Instead of directly finishing the
// task, a task change listener is used to notify SystemUI so the action can be
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4a7edee..459a8d6 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4131,6 +4131,10 @@
return true;
}
+ if (task.isOrganized()) {
+ return true;
+ }
+
// We need to use the task's dim bounds (which is derived from the visible bounds of
// its apps windows) for any touch-related tests. Can't use the task's original
// bounds because it might be adjusted to fit the content frame. One example is when
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 8edcd2f..7c47e50 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -32,7 +32,6 @@
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.util.Slog;
import android.util.SparseArray;
import android.window.ITaskOrganizer;
@@ -46,7 +45,6 @@
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
-import java.util.Set;
import java.util.WeakHashMap;
/**
@@ -88,6 +86,7 @@
private final DeathRecipient mDeathRecipient;
private final ArrayList<Task> mOrganizedTasks = new ArrayList<>();
private final int mUid;
+ private boolean mInterceptBackPressedOnTaskRoot;
TaskOrganizerState(ITaskOrganizer organizer, int uid) {
mOrganizer = organizer;
@@ -100,6 +99,10 @@
mUid = uid;
}
+ void setInterceptBackPressedOnTaskRoot(boolean interceptBackPressed) {
+ mInterceptBackPressedOnTaskRoot = interceptBackPressed;
+ }
+
void addTask(Task t) {
mOrganizedTasks.add(t);
try {
@@ -473,6 +476,41 @@
}
}
+ @Override
+ public void setInterceptBackPressedOnTaskRoot(ITaskOrganizer organizer,
+ boolean interceptBackPressed) {
+ enforceStackPermission("setInterceptBackPressedOnTaskRoot()");
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
+ if (state != null) {
+ state.setInterceptBackPressedOnTaskRoot(interceptBackPressed);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ public boolean handleInterceptBackPressedOnTaskRoot(Task task) {
+ if (task == null || !task.isOrganized()) {
+ return false;
+ }
+
+ final TaskOrganizerState state = mTaskOrganizerStates.get(task.mTaskOrganizer.asBinder());
+ if (!state.mInterceptBackPressedOnTaskRoot) {
+ return false;
+ }
+
+ try {
+ state.mOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception sending interceptBackPressedOnTaskRoot callback" + e);
+ }
+ return true;
+ }
+
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.print(prefix); pw.println("TaskOrganizerController:");
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index ed400ea..bc1f925 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -1047,5 +1047,8 @@
}
}
}
+ @Override
+ public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
+ }
};
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index 4cc84a6..f05acce 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -50,6 +50,7 @@
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
+import android.app.IRequestFinishCallback;
import android.app.PictureInPictureParams;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -420,6 +421,10 @@
@Override
public void onTaskInfoChanged(RunningTaskInfo info) throws RemoteException {
}
+
+ @Override
+ public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
+ }
};
mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
@@ -474,6 +479,10 @@
lastReportedTiles.add(info);
called[0] = true;
}
+
+ @Override
+ public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
+ }
};
mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
@@ -531,6 +540,10 @@
public void onTaskInfoChanged(RunningTaskInfo info) {
lastReportedTiles.put(info.token.asBinder(), info);
}
+
+ @Override
+ public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
+ }
};
mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(
listener, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
@@ -751,6 +764,9 @@
@Override
public void onTaskInfoChanged(RunningTaskInfo info) {
}
+ @Override
+ public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
+ }
};
private ActivityRecord makePipableActivity() {
@@ -827,4 +843,31 @@
task.removeImmediately();
verify(organizer).onTaskVanished(any());
}
+
+ @Test
+ public void testInterceptBackPressedOnTaskRoot() throws RemoteException {
+ final ActivityStack stack = createStack();
+ final Task task = createTask(stack);
+ final ActivityRecord activity = WindowTestUtils.createActivityRecordInTask(
+ stack.mDisplayContent, task);
+ final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
+
+ // Setup the task to be controlled by the MW mode organizer
+ stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+ assertTrue(stack.isOrganized());
+
+ // Verify a back pressed does not call the organizer
+ mWm.mAtmService.onBackPressedOnTaskRoot(activity.token,
+ new IRequestFinishCallback.Default());
+ verify(organizer, never()).onBackPressedOnTaskRoot(any());
+
+ // Enable intercepting back
+ mWm.mAtmService.mTaskOrganizerController.setInterceptBackPressedOnTaskRoot(organizer,
+ true);
+
+ // Verify now that the back press does call the organizer
+ mWm.mAtmService.onBackPressedOnTaskRoot(activity.token,
+ new IRequestFinishCallback.Default());
+ verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
+ }
}