Merge "TaskOrganizer: Add WINDOWING_MODE_MULTI_WINDOW support"
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 283be40..66c65e2 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -106,9 +107,11 @@
      * and receive taskVanished callbacks in the process.
      */
     void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode) {
-        if (windowingMode != WINDOWING_MODE_PINNED) {
+        if (windowingMode != WINDOWING_MODE_PINNED &&
+            windowingMode != WINDOWING_MODE_MULTI_WINDOW) {
             throw new UnsupportedOperationException(
-                    "As of now only Pinned windowing mode is supported for registerTaskOrganizer");
+                    "As of now only Pinned and Multiwindow windowing modes are"
+                    + " supported for registerTaskOrganizer");
 
         }
         clearIfNeeded(windowingMode);
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 c9fd79f..9e80cf2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -16,9 +16,9 @@
 
 package com.android.server.wm;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
@@ -63,20 +63,24 @@
 @Presubmit
 @RunWith(WindowTestRunner.class)
 public class TaskOrganizerTests extends WindowTestsBase {
-    private ITaskOrganizer makeAndRegisterMockOrganizer() {
+    private ITaskOrganizer registerMockOrganizer(int windowingMode) {
         final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
         when(organizer.asBinder()).thenReturn(new Binder());
 
-        mWm.mAtmService.registerTaskOrganizer(organizer, WINDOWING_MODE_PINNED);
+        mWm.mAtmService.registerTaskOrganizer(organizer, windowingMode);
 
         return organizer;
     }
 
+    private ITaskOrganizer registerMockOrganizer() {
+        return registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
+    }
+
     @Test
     public void testAppearVanish() throws RemoteException {
         final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stack, 0 /* userId */);
-        final ITaskOrganizer organizer = makeAndRegisterMockOrganizer();
+        final ITaskOrganizer organizer = registerMockOrganizer();
 
         task.setTaskOrganizer(organizer);
         verify(organizer).taskAppeared(any(), any());
@@ -89,8 +93,8 @@
     public void testSwapOrganizer() throws RemoteException {
         final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stack, 0 /* userId */);
-        final ITaskOrganizer organizer = makeAndRegisterMockOrganizer();
-        final ITaskOrganizer organizer2 = makeAndRegisterMockOrganizer();
+        final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
+        final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED);
 
         task.setTaskOrganizer(organizer);
         verify(organizer).taskAppeared(any(), any());
@@ -100,10 +104,24 @@
     }
 
     @Test
+    public void testSwapWindowingModes() throws RemoteException {
+        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final Task task = createTaskInStack(stack, 0 /* userId */);
+        final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
+        final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED);
+ 
+        stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        verify(organizer).taskAppeared(any(), any());
+        stack.setWindowingMode(WINDOWING_MODE_PINNED);
+        verify(organizer).taskVanished(any());
+        verify(organizer2).taskAppeared(any(), any());
+    }
+
+    @Test
     public void testClearOrganizer() throws RemoteException {
         final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stack, 0 /* userId */);
-        final ITaskOrganizer organizer = makeAndRegisterMockOrganizer();
+        final ITaskOrganizer organizer = registerMockOrganizer();
 
         stack.setTaskOrganizer(organizer);
         verify(organizer).taskAppeared(any(), any());
@@ -116,7 +134,7 @@
 
     @Test
     public void testRegisterTaskOrganizerStackWindowingModeChanges() throws RemoteException {
-        final ITaskOrganizer organizer = makeAndRegisterMockOrganizer();
+        final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_PINNED);
 
         final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stack, 0 /* userId */);
diff --git a/tests/TaskOrganizerTest/AndroidManifest.xml b/tests/TaskOrganizerTest/AndroidManifest.xml
index 0cb6c10..a77d7ee 100644
--- a/tests/TaskOrganizerTest/AndroidManifest.xml
+++ b/tests/TaskOrganizerTest/AndroidManifest.xml
@@ -19,5 +19,11 @@
       <service android:name=".TaskOrganizerPipTest"
                android:exported="true">
       </service>
+      <activity android:name="TaskOrganizerMultiWindowTest" android:label="TaskOrganizer MW Test">
+        <intent-filter>
+          <action android:name="android.intent.action.MAIN"/>
+          <category android:name="android.intent.category.LAUNCHER"/>
+        </intent-filter>
+      </activity>
     </application>
 </manifest>
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
new file mode 100644
index 0000000..bc8d3c3
--- /dev/null
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 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.test.taskembed;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+
+import android.app.ActivityManager;
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.ITaskOrganizer;
+import android.view.IWindowContainer;
+import android.view.SurfaceControl;
+import android.view.SurfaceHolder;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+public class TaskOrganizerMultiWindowTest extends Activity {
+    class TaskLaunchingView extends TaskView {
+        TaskLaunchingView(Context c, ITaskOrganizer o, int windowingMode) {
+            super(c, o, windowingMode);
+        }
+
+        @Override
+        public void surfaceChanged(SurfaceHolder h, int format, int width, int height) {
+            startCalculatorActivity(width, height);
+        }
+    }
+    TaskView mView;
+
+    class Organizer extends ITaskOrganizer.Stub {
+        @Override
+        public void taskAppeared(IWindowContainer wc, ActivityManager.RunningTaskInfo ti) {
+            mView.reparentTask(wc);
+        }
+        public void taskVanished(IWindowContainer wc) {
+        }
+        public void transactionReady(int id, SurfaceControl.Transaction t) {
+        }
+    }
+
+    Organizer mOrganizer = new Organizer();
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mView = new TaskLaunchingView(this, mOrganizer, WINDOWING_MODE_MULTI_WINDOW);
+        setContentView(mView);
+    }
+
+    Intent makeCalculatorIntent() {
+        Intent intent = new Intent();
+        intent.setAction(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_APP_CALCULATOR);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        return intent;
+    }
+
+    Bundle makeLaunchOptions(int width, int height) {
+        ActivityOptions o = ActivityOptions.makeBasic();
+        o.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        o.setLaunchBounds(new Rect(0, 0, width, height));
+        return o.toBundle();
+    }
+
+    void startCalculatorActivity(int width, int height) {
+        startActivity(makeCalculatorIntent(), makeLaunchOptions(width, height));
+    }
+}
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
index 6ffa19d..fc1be28 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
@@ -16,6 +16,8 @@
 
 package com.android.test.taskembed;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.Service;
@@ -38,48 +40,11 @@
     static final int PIP_WIDTH  = 640;
     static final int PIP_HEIGHT = 360;
 
-    class PipOrgView extends SurfaceView implements SurfaceHolder.Callback {
-        PipOrgView(Context c) {
-            super(c);
-            getHolder().addCallback(this);
-            setZOrderOnTop(true);
-        }
-        @Override
-        public void surfaceCreated(SurfaceHolder holder) {
-            try {
-                ActivityTaskManager.getService().registerTaskOrganizer(mOrganizer,
-                        WindowConfiguration.WINDOWING_MODE_PINNED);
-            } catch (Exception e) {
-            }
-        }
-
-        @Override
-        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-        }
-
-        @Override
-        public void surfaceDestroyed(SurfaceHolder holder) {
-        }
-
-        void reparentTask(IWindowContainer wc) {
-            SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-            SurfaceControl leash = null;
-            try {
-                leash = wc.getLeash();
-            } catch (Exception e) {
-                // System server died.. oh well
-            }
-            t.reparent(leash, getSurfaceControl())
-                .setPosition(leash, 0, 0)
-                .apply();
-        }
-    }
-
-    PipOrgView mPipView;
+    TaskView mTaskView;
 
     class Organizer extends ITaskOrganizer.Stub {
         public void taskAppeared(IWindowContainer wc, ActivityManager.RunningTaskInfo ti) {
-            mPipView.reparentTask(wc);
+            mTaskView.reparentTask(wc);
 
             final WindowContainerTransaction wct = new WindowContainerTransaction();
             wct.scheduleFinishEnterPip(wc, new Rect(0, 0, PIP_WIDTH, PIP_HEIGHT));
@@ -113,8 +78,8 @@
         FrameLayout layout = new FrameLayout(this);
         ViewGroup.LayoutParams lp =
             new ViewGroup.LayoutParams(PIP_WIDTH, PIP_HEIGHT);
-        mPipView = new PipOrgView(this);
-        layout.addView(mPipView, lp);
+        mTaskView = new TaskView(this, mOrganizer, WINDOWING_MODE_PINNED);
+        layout.addView(mTaskView, lp);
 
         WindowManager wm = getSystemService(WindowManager.class);
         wm.addView(layout, wlp);
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
new file mode 100644
index 0000000..ff73340
--- /dev/null
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
@@ -0,0 +1,73 @@
+/*
+ * 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.test.taskembed;
+
+import android.app.ActivityTaskManager;
+import android.content.Context;
+import android.view.ITaskOrganizer;
+import android.view.IWindowContainer;
+import android.view.SurfaceControl;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+/**
+ * Simple SurfaceView wrapper which registers a TaskOrganizer
+ * after it's Surface is ready.
+ */
+class TaskView extends SurfaceView implements SurfaceHolder.Callback {
+    final ITaskOrganizer mTaskOrganizer;
+    final int mWindowingMode;
+
+    TaskView(Context c, ITaskOrganizer o, int windowingMode) {
+        super(c);
+        getHolder().addCallback(this);
+        setZOrderOnTop(true);
+
+        mTaskOrganizer = o;
+        mWindowingMode = windowingMode;
+    }
+
+    @Override
+    public void surfaceCreated(SurfaceHolder holder) {
+        try {
+            ActivityTaskManager.getService().registerTaskOrganizer(mTaskOrganizer,
+                    mWindowingMode);
+        } catch (Exception e) {
+        }
+    }
+
+    @Override
+    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+    }
+
+    @Override
+    public void surfaceDestroyed(SurfaceHolder holder) {
+    }
+
+    void reparentTask(IWindowContainer wc) {
+        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+        SurfaceControl leash = null;
+        try {
+            leash = wc.getLeash();
+        } catch (Exception e) {
+            // System server died.. oh well
+        }
+        t.reparent(leash, getSurfaceControl())
+            .setPosition(leash, 0, 0)
+            .apply();
+    }
+}