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());
+    }
 }