Add resizing tasks synchronously flicker tests

The test app will launch two tasks on two SurfaceViews and use
TaskOrganizer that implements BLASTSyncEngine to resize two
tasks synchronously.

We could verify it from the layersTrace to ensure the layers of the
two tasks could apply resizing at same transaction.

Bug: 168505972
Test: enable mUseBLASTSync, atest ResizeTasksSyncTest
Change-Id: I815325e37f3ce1e70fb5b51ec32f82a0088c4943
diff --git a/tests/TaskOrganizerTest/Android.bp b/tests/TaskOrganizerTest/Android.bp
index 8a13dbc..91900626 100644
--- a/tests/TaskOrganizerTest/Android.bp
+++ b/tests/TaskOrganizerTest/Android.bp
@@ -16,7 +16,20 @@
 
 android_test {
     name: "TaskOrganizerTest",
-    srcs: ["**/*.java"],
+    srcs: ["**/*.java","**/*.kt"],
+    manifest: "AndroidManifest.xml",
+    test_config: "AndroidTest.xml",
     platform_apis: true,
     certificate: "platform",
-}
+
+    static_libs: [
+        "androidx.appcompat_appcompat",
+        "androidx.test.rules",
+        "androidx.test.runner",
+        "androidx.test.ext.junit",
+        "kotlin-stdlib",
+        "kotlinx-coroutines-android",
+        "flickerlib",
+        "truth-prebuilt",
+    ],
+}
\ No newline at end of file
diff --git a/tests/TaskOrganizerTest/AndroidManifest.xml b/tests/TaskOrganizerTest/AndroidManifest.xml
index 451a55f..1f1bd3e 100644
--- a/tests/TaskOrganizerTest/AndroidManifest.xml
+++ b/tests/TaskOrganizerTest/AndroidManifest.xml
@@ -16,17 +16,41 @@
     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"/>
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+    <!-- Enable / Disable tracing !-->
+    <uses-permission android:name="android.permission.DUMP" />
     <application>
-      <service android:name=".TaskOrganizerPipTest"
-           android:exported="true">
-      </service>
       <activity android:name="TaskOrganizerMultiWindowTest"
            android:label="TaskOrganizer MW Test"
-           android:exported="true">
+           android:exported="true"
+           android:excludeFromRecents="true">
         <intent-filter>
           <action android:name="android.intent.action.MAIN"/>
           <category android:name="android.intent.category.LAUNCHER"/>
         </intent-filter>
       </activity>
+        <activity android:name="TaskOrganizerMultiWindowTest$TestActivity1"
+                  android:label="Test Activity 1"
+                  android:exported="false"
+                  android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen"
+                  android:taskAffinity="com.android.test.taskembed.task1"
+                  android:excludeFromRecents="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+            </intent-filter>
+        </activity>
+        <activity android:name="TaskOrganizerMultiWindowTest$TestActivity2"
+                  android:label="Test Activity 2"
+                  android:exported="false"
+                  android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen"
+                  android:taskAffinity="com.android.test.taskembed.task2"
+                  android:excludeFromRecents="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+            </intent-filter>
+        </activity>
     </application>
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.test.taskembed"
+                     android:label="TaskOrganizerTest">
+    </instrumentation>
 </manifest>
diff --git a/tests/TaskOrganizerTest/AndroidTest.xml b/tests/TaskOrganizerTest/AndroidTest.xml
new file mode 100644
index 0000000..45fd8b0
--- /dev/null
+++ b/tests/TaskOrganizerTest/AndroidTest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs TaskOrganizer Test">
+    <option name="test-tag" value="TaskOrganizerTest" />
+    <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+        <!-- keeps the screen on during tests -->
+        <option name="screen-always-on" value="on" />
+        <!-- prevents the phone from restarting -->
+        <option name="force-skip-system-props" value="true" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="false"/>
+        <option name="test-file-name" value="TaskOrganizerTest.apk"/>
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="com.android.test.taskembed"/>
+        <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
+        <option name="shell-timeout" value="6600s" />
+        <option name="test-timeout" value="6000s" />
+        <option name="hidden-api-checks" value="false" />
+    </test>
+</configuration>
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
new file mode 100644
index 0000000..abccd6cf
--- /dev/null
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
@@ -0,0 +1,111 @@
+/*
+ * 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.Instrumentation
+import android.graphics.Rect
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.runner.AndroidJUnit4
+import com.android.server.wm.flicker.monitor.LayersTraceMonitor
+import com.android.server.wm.flicker.monitor.withSFTracing
+import com.android.server.wm.flicker.traces.layers.LayersTraceSubject.Companion.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import java.util.concurrent.CountDownLatch
+import org.junit.Assert.assertNotEquals
+
+@RunWith(AndroidJUnit4::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class ResizeTasksSyncTest {
+    @get:Rule
+    var scenarioRule: ActivityScenarioRule<TaskOrganizerMultiWindowTest> =
+            ActivityScenarioRule<TaskOrganizerMultiWindowTest>(
+                    TaskOrganizerMultiWindowTest::class.java)
+
+    protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+
+    @Before
+    fun setup() {
+        val tmpDir = instrumentation.targetContext.dataDir.toPath()
+        LayersTraceMonitor(tmpDir).stop()
+        val firstTaskBounds = Rect(0, 0, 1080, 1000)
+        val secondTaskBounds = Rect(0, 1000, 1080, 2000)
+
+        lateinit var surfaceReadyLatch: CountDownLatch
+        scenarioRule.getScenario().onActivity {
+            surfaceReadyLatch = it.openTaskView(firstTaskBounds, secondTaskBounds)
+        }
+        surfaceReadyLatch.await()
+    }
+
+    @After
+    fun teardown() {
+        scenarioRule.getScenario().close()
+    }
+
+    @Test
+    fun testResizeTwoTaskSync() {
+        val firstBounds = Rect(0, 0, 1080, 800)
+        val secondBounds = Rect(0, 1000, 1080, 1800)
+
+        val trace = withSFTracing(instrumentation, TRACE_FLAGS) {
+            lateinit var resizeReadyLatch: CountDownLatch
+            scenarioRule.getScenario().onActivity {
+                resizeReadyLatch = it.resizeTaskView(firstBounds, secondBounds)
+            }
+            resizeReadyLatch.await()
+        }
+
+        // find the frame which match resized buffer size.
+        var frame: Long = -1
+        loop@ for (trace in trace.entries) {
+            for (layer in trace.flattenedLayers) {
+                if (layer.proto.activeBuffer != null &&
+                        layer.proto.activeBuffer.width == firstBounds.width() &&
+                        layer.proto.activeBuffer.height == firstBounds.height()) {
+                    frame = layer.proto.currFrame
+                    break@loop
+                }
+            }
+        }
+        assertNotEquals(-1, frame)
+        // layer bounds should be related to parent surfaceview.
+        secondBounds.offsetTo(0, 0)
+
+        // verify buffer size should be changed to expected values.
+        assertThat(trace).layer(FIRST_ACTIVITY, frame).also {
+            it.hasLayerSize(firstBounds)
+            it.hasBufferSize(firstBounds)
+        }
+
+        assertThat(trace).layer(SECOND_ACTIVITY, frame).also {
+            it.hasLayerSize(secondBounds)
+            it.hasBufferSize(secondBounds)
+        }
+    }
+
+    companion object {
+        private const val TRACE_FLAGS = 0x1 // TRACE_CRITICAL
+        private const val FIRST_ACTIVITY = "Activity1"
+        private const val SECOND_ACTIVITY = "Activity2"
+    }
+}
\ No newline at end of file
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
index ca723b8..0cf5a41 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -16,189 +16,182 @@
 
 package com.android.test.taskembed;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
 
 import android.app.Activity;
 import android.app.ActivityManager;
-import android.app.ActivityOptions;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.view.Gravity;
-import android.view.MotionEvent;
 import android.view.SurfaceControl;
-import android.view.SurfaceHolder;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
+import android.widget.FrameLayout;
+import android.widget.TextView;
 import android.window.TaskOrganizer;
-import android.window.WindowContainerTransaction;
 import android.window.WindowContainerTransactionCallback;
 
+import java.util.concurrent.CountDownLatch;
+
 public class TaskOrganizerMultiWindowTest extends Activity {
-    static class SplitLayout extends LinearLayout implements View.OnTouchListener {
-        View mView1;
-        View mView2;
-        View mDividerView;
-
-        public boolean onTouch(View v, MotionEvent e) {
-            if (e.getAction() != MotionEvent.ACTION_UP) {
-                return true;
-            }
-
-            float x = e.getRawX(0);
-            float ratio = (float) x / (float) getWidth() ;
-            ratio = 1-ratio;
-
-            LinearLayout.LayoutParams lp1 =
-                new LinearLayout.LayoutParams(0,
-                        ViewGroup.LayoutParams.WRAP_CONTENT, ratio-0.02f);
-            LinearLayout.LayoutParams lp2 =
-                new LinearLayout.LayoutParams(0,
-                        ViewGroup.LayoutParams.WRAP_CONTENT, 1-ratio-0.02f);
-            updateViewLayout(mView1, lp2);
-            updateViewLayout(mView2, lp1);
-            return true;
-        }
-
-        SplitLayout(Context c, View v1, View v2) {
-            super(c);
-            LinearLayout.LayoutParams lp1 =
-                new LinearLayout.LayoutParams(0,
-                        ViewGroup.LayoutParams.WRAP_CONTENT, 0.48f);
-            LinearLayout.LayoutParams lp3 =
-                new LinearLayout.LayoutParams(0,
-                        ViewGroup.LayoutParams.WRAP_CONTENT, 0.48f);
-            LinearLayout.LayoutParams lp2 =
-                new LinearLayout.LayoutParams(0,
-                        ViewGroup.LayoutParams.FILL_PARENT, 0.04f);
-            lp2.gravity = Gravity.CENTER;
-
-            setWeightSum(1);
-
-            mView1 = v1;
-            mView2 = v2;
-            addView(mView1, lp1);
-
-            mDividerView = new View(getContext());
-            mDividerView.setBackgroundColor(Color.BLACK);
-            addView(mDividerView, lp2);
-            mDividerView.setOnTouchListener(this);
-
-            addView(mView2, lp3);
-        }
-    }
-
-    class ResizingTaskView extends TaskView {
-        final Intent mIntent;
-        boolean launched = false;
-        ResizingTaskView(Context c, Intent i) {
-            super(c);
-            mIntent = i;
-        }
-
-        @Override
-        public void surfaceChanged(SurfaceHolder h, int format, int width, int height) {
-            if (!launched) {
-                launchOrganizedActivity(mIntent, width, height);
-                launched = true;
-            } else {
-                resizeTask(width, height);
-            }
-        }
-
-        void resizeTask(int width, int height) {
-            final WindowContainerTransaction wct = new WindowContainerTransaction();
-            wct.setBounds(mWc, new Rect(0, 0, width, height));
-            try {
-                mOrganizer.applySyncTransaction(wct, mOrganizer.mTransactionCallback);
-            } catch (Exception e) {
-                // Oh well
-            }
-        }
-    }
-
-    private TaskView mTaskView1;
-    private TaskView mTaskView2;
-    private boolean mGotFirstTask = false;
+    private CountDownLatch mTasksReadyLatch;
+    private CountDownLatch mTasksResizeLatch;
 
     class Organizer extends TaskOrganizer {
-        private int receivedTransactions = 0;
-        SurfaceControl.Transaction mergedTransaction = new SurfaceControl.Transaction();
+        private int mReceivedTransactions = 0;
+        private SurfaceControl.Transaction mMergedTransaction = new SurfaceControl.Transaction();
         WindowContainerTransactionCallback mTransactionCallback =
                 new WindowContainerTransactionCallback() {
             @Override
             public void onTransactionReady(int id, SurfaceControl.Transaction t) {
-                mergedTransaction.merge(t);
-                receivedTransactions++;
-                if (receivedTransactions == 2) {
-                    mergedTransaction.apply();
-                    receivedTransactions = 0;
+                mMergedTransaction.merge(t);
+                mReceivedTransactions++;
+                if (mReceivedTransactions == 2) {
+                    mReceivedTransactions = 0;
+                    mMergedTransaction.apply(true);
+                    if (mTasksResizeLatch != null) {
+                        mTasksResizeLatch.countDown();
+                    }
                 }
             }
         };
 
         @Override
         public void onTaskAppeared(ActivityManager.RunningTaskInfo ti, SurfaceControl leash) {
-            if (!mGotFirstTask) {
-                mTaskView1.reparentTask(ti.token, leash);
-                mGotFirstTask = true;
-            } else {
-                mTaskView2.reparentTask(ti.token, leash);
+            if (ti.baseActivity == null) {
+                return;
             }
+
+            final String clsName = ti.baseActivity.getClassName();
+            if (clsName.contentEquals(TestActivity1.class.getName())) {
+                mTaskView1.reparentTask(ti.token, leash);
+                mOrganizer.setInterceptBackPressedOnTaskRoot(ti.token, true);
+                mTasksReadyLatch.countDown();
+            } else if (clsName.contentEquals(TestActivity2.class.getName())) {
+                mTaskView2.reparentTask(ti.token, leash);
+                mOrganizer.setInterceptBackPressedOnTaskRoot(ti.token, true);
+                mTasksReadyLatch.countDown();
+            }
+        }
+
+        @Override
+        public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
+            getMainThreadHandler().post(() -> {
+                finish();
+            });
         }
     }
 
     private Organizer mOrganizer = new Organizer();
-
+    private FrameLayout mTasksLayout;
+    private TaskView mTaskView1;
+    private TaskView mTaskView2;
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        getWindow().getAttributes().layoutInDisplayCutoutMode =
+                LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+
+        mTasksLayout = new FrameLayout(this);
+        setContentView(mTasksLayout);
 
         mOrganizer.registerOrganizer();
-
-        mTaskView1 = new ResizingTaskView(this, makeSettingsIntent());
-        mTaskView2 = new ResizingTaskView(this, makeContactsIntent());
-        View splitView = new SplitLayout(this, mTaskView1, mTaskView2);
-
-        setContentView(splitView);
     }
 
     @Override
     protected void onDestroy() {
         super.onDestroy();
         mOrganizer.unregisterOrganizer();
+        mTasksLayout.removeAllViews();
     }
 
-    private void addFlags(Intent intent) {
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
-    }
-
-    private Intent makeSettingsIntent() {
-        Intent intent = new Intent();
-        intent.setAction(android.provider.Settings.ACTION_SETTINGS);
-        addFlags(intent);
+    private Intent makeActivityIntent(final Class<?> clazz) {
+        Intent intent = new Intent(this, clazz);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION
+                | Intent.FLAG_ACTIVITY_CLEAR_TASK);
         return intent;
     }
 
-    private Intent makeContactsIntent() {
-        Intent intent = new Intent();
-        intent.setAction(Intent.ACTION_MAIN);
-        intent.addCategory(Intent.CATEGORY_APP_CONTACTS);
-        addFlags(intent);
-        return intent;
+    public CountDownLatch openTaskView(Rect firstBounds, Rect secondBounds) {
+        mTasksReadyLatch = new CountDownLatch(2);
+        mTaskView1 = new TaskView(this, mOrganizer, makeActivityIntent(TestActivity1.class));
+        mTaskView1.setBackgroundColor(Color.DKGRAY);
+
+        FrameLayout.LayoutParams viewLayout1 =
+                new FrameLayout.LayoutParams(firstBounds.width(), firstBounds.height(),
+                        Gravity.TOP | Gravity.LEFT);
+        viewLayout1.setMargins(firstBounds.left, firstBounds.top, 0, 0);
+        mTasksLayout.addView(mTaskView1, viewLayout1);
+
+        mTaskView2 = new TaskView(this, mOrganizer, makeActivityIntent(TestActivity2.class));
+        mTaskView2.setBackgroundColor(Color.LTGRAY);
+        FrameLayout.LayoutParams viewLayout2 =
+                new FrameLayout.LayoutParams(secondBounds.width(), secondBounds.height(),
+                        Gravity.TOP | Gravity.LEFT);
+        viewLayout2.setMargins(secondBounds.left, secondBounds.top, 0, 0);
+        mTasksLayout.addView(mTaskView2, viewLayout2);
+        return mTasksReadyLatch;
     }
 
-    private 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();
+    public CountDownLatch resizeTaskView(Rect firstBounds, Rect secondBounds) {
+        mTasksResizeLatch = new CountDownLatch(1);
+
+        mTaskView1.resizeTask(firstBounds.width(), firstBounds.height());
+        mTaskView2.resizeTask(secondBounds.width(), secondBounds.height());
+
+        return mTasksResizeLatch;
     }
 
-    private void launchOrganizedActivity(Intent i, int width, int height) {
-        startActivity(i, makeLaunchOptions(width, height));
+    static class InstrumentedTextView extends TextView {
+        private final boolean mSlowDraw;
+        InstrumentedTextView(Context context, boolean slowDraw) {
+            super(context);
+            mSlowDraw = slowDraw;
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            if (mSlowDraw) {
+                try {
+                    Thread.sleep(20);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    public static class TestActivity1 extends Activity {
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            getWindow().getAttributes().layoutInDisplayCutoutMode =
+                    LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+
+            TextView v = new InstrumentedTextView(this, true);
+            v.setText("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
+                    + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz");
+            v.setBackgroundColor(Color.RED);
+            v.setTextColor(Color.BLACK);
+            setContentView(v);
+        }
+    }
+
+    public static class TestActivity2 extends Activity {
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            getWindow().getAttributes().layoutInDisplayCutoutMode =
+                    LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+            TextView v = new InstrumentedTextView(this, false);
+            v.setText("ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                    + "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ");
+            v.setBackgroundColor(Color.GREEN);
+            v.setTextColor(Color.BLACK);
+            setContentView(v);
+        }
     }
 }
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
deleted file mode 100644
index 5ec9493..0000000
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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_PINNED;
-
-import android.app.ActivityManager;
-import android.app.Service;
-import android.content.Intent;
-import android.graphics.Rect;
-import android.os.IBinder;
-import android.view.SurfaceControl;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-import android.window.TaskOrganizer;
-import android.window.WindowContainerTransaction;
-
-public class TaskOrganizerPipTest extends Service {
-    private static final int PIP_WIDTH  = 640;
-    private static final int PIP_HEIGHT = 360;
-
-    private TaskView mTaskView;
-
-    class Organizer extends TaskOrganizer {
-        public void onTaskAppeared(ActivityManager.RunningTaskInfo ti, SurfaceControl leash) {
-            mTaskView.reparentTask(ti.token, leash);
-
-            final WindowContainerTransaction wct = new WindowContainerTransaction();
-            wct.scheduleFinishEnterPip(ti.token, new Rect(0, 0, PIP_WIDTH, PIP_HEIGHT));
-            applyTransaction(wct);
-        }
-    }
-
-    private Organizer mOrganizer = new Organizer();
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return null;
-    }
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-
-        mOrganizer.registerOrganizer();
-
-        final WindowManager.LayoutParams wlp = new WindowManager.LayoutParams();
-        wlp.setTitle("TaskOrganizerPipTest");
-        wlp.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-        wlp.width = wlp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
-
-        FrameLayout layout = new FrameLayout(this);
-        ViewGroup.LayoutParams lp =
-            new ViewGroup.LayoutParams(PIP_WIDTH, PIP_HEIGHT);
-        mTaskView = new TaskView(this);
-        layout.addView(mTaskView, lp);
-
-        WindowManager wm = getSystemService(WindowManager.class);
-        wm.addView(layout, wlp);
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        mOrganizer.unregisterOrganizer();
-    }
-}
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
index 208018c..4ef91c7 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
@@ -16,65 +16,113 @@
 
 package com.android.test.taskembed;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
+import android.app.ActivityOptions;
 import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Bundle;
 import android.view.SurfaceControl;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
 
 /**
  * Simple SurfaceView wrapper which registers a TaskOrganizer
  * after it's Surface is ready.
  */
-class TaskView extends SurfaceView implements SurfaceHolder.Callback {
-    WindowContainerToken mWc;
+class TaskView extends SurfaceView {
+    private WindowContainerToken mWc;
+    private Context mContext;
     private SurfaceControl mLeash;
+    private TaskOrganizerMultiWindowTest.Organizer mOrganizer;
+    private Intent mIntent;
+    private boolean mLaunched = false;
 
-    private boolean mSurfaceCreated = false;
-    private boolean mNeedsReparent;
-
-    TaskView(Context c) {
+    TaskView(Context c, TaskOrganizerMultiWindowTest.Organizer organizer,
+            Intent intent) {
         super(c);
-        getHolder().addCallback(this);
+        mContext = c;
+        mOrganizer = organizer;
+        mIntent = intent;
+        getHolder().addCallback(
+                new SurfaceHolder.Callback() {
+                    @Override
+                    public void surfaceCreated(SurfaceHolder holder) {}
+
+                    @Override
+                    public void surfaceChanged(SurfaceHolder holder,
+                            int format, int width, int height) {
+                        if (!mLaunched) {
+                            launchOrganizedActivity(mIntent, width, height);
+                            mLaunched = true;
+                        } else {
+                            resizeTask(width, height);
+                        }
+                    }
+
+                    @Override
+                    public void surfaceDestroyed(SurfaceHolder holder) {}
+                }
+        );
         setZOrderOnTop(true);
     }
 
-    @Override
-    public void surfaceCreated(SurfaceHolder holder) {
-        mSurfaceCreated = true;
-        if (mNeedsReparent) {
-            mNeedsReparent = false;
-            reparentLeash();
+    private void launchOrganizedActivity(Intent i, int width, int height) {
+        mContext.startActivity(i, makeLaunchOptions(width, height));
+    }
+
+    private Bundle makeLaunchOptions(int width, int height) {
+        ActivityOptions o = ActivityOptions.makeBasic();
+        o.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        o.setLaunchBounds(new Rect(0, 0, width, height));
+        o.setTaskOverlay(true, true);
+        o.setTaskAlwaysOnTop(true);
+        return o.toBundle();
+    }
+
+    void resizeTask(int width, int height) {
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
+        wct.setBounds(mWc, new Rect(0, 0, width, height)).setHidden(mWc, false);
+        try {
+            mOrganizer.applySyncTransaction(wct, mOrganizer.mTransactionCallback);
+        } catch (Exception e) {
+            // Oh well
         }
     }
 
-    @Override
-    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-    }
-
-    @Override
-    public void surfaceDestroyed(SurfaceHolder holder) {
+    void hideTask() {
+        if (mWc == null) {
+            return;
+        }
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
+        wct.setWindowingMode(mWc, WINDOWING_MODE_UNDEFINED).setHidden(mWc, true);
+        try {
+            mOrganizer.applySyncTransaction(wct, mOrganizer.mTransactionCallback);
+        } catch (Exception e) {
+            // Oh well
+        }
+        releaseLeash();
     }
 
     void reparentTask(WindowContainerToken wc, SurfaceControl leash) {
         mWc = wc;
         mLeash = leash;
-        if (!mSurfaceCreated) {
-            mNeedsReparent = true;
-        } else {
-            reparentLeash();
-        }
+        reparentLeash();
     }
 
-    private void reparentLeash() {
+    void reparentLeash() {
         SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-        if (mLeash == null) {
-            return;
-        }
-
         t.reparent(mLeash, getSurfaceControl())
-            .setPosition(mLeash, 0, 0)
             .show(mLeash)
             .apply();
     }
+
+    void releaseLeash() {
+        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+        t.remove(mLeash).apply();
+    }
 }