Merge "Add RESERVE_NEW_UI_EVENT_ID field to EventEnum interface." into sc-v2-dev
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index ab88b2b..3e2fb63 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -96,7 +96,11 @@
                 public void onDraw() {
                     View view = mLauncher.getDragLayer();
                     ViewRootImpl viewRootImpl = view.getViewRootImpl();
-                    setSurface(viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null);
+                    boolean applied = setSurface(
+                            viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null);
+                    if (!applied) {
+                        dispatchTransactionSurface(mDepth);
+                    }
                     view.post(() -> view.getViewTreeObserver().removeOnDrawListener(this));
                 }
             };
@@ -202,20 +206,22 @@
 
     /**
      * Sets the specified app target surface to apply the blur to.
+     * @return true when surface was valid and transaction was dispatched.
      */
-    public void setSurface(SurfaceControl surface) {
+    public boolean setSurface(SurfaceControl surface) {
         // Set launcher as the SurfaceControl when we don't need an external target anymore.
         if (surface == null) {
             ViewRootImpl viewRootImpl = mLauncher.getDragLayer().getViewRootImpl();
             surface = viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null;
         }
-
         if (mSurface != surface) {
             mSurface = surface;
             if (surface != null) {
                 dispatchTransactionSurface(mDepth);
+                return true;
             }
         }
+        return false;
     }
 
     @Override
@@ -229,6 +235,8 @@
             setDepth(toDepth);
         } else if (toState == LauncherState.OVERVIEW) {
             dispatchTransactionSurface(mDepth);
+        } else if (toState == LauncherState.BACKGROUND_APP) {
+            mLauncher.getDragLayer().getViewTreeObserver().addOnDrawListener(mOnDrawListener);
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 0afa480..b7c5db2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -123,11 +123,9 @@
          */
         public void updateInsetsTouchability(InsetsInfo insetsInfo) {
             insetsInfo.touchableRegion.setEmpty();
-            if (mActivity.isThreeButtonNav()) {
-                // Always have nav buttons be touchable
-                mControllers.navbarButtonsViewController.addVisibleButtonsRegion(
-                        mTaskbarDragLayer, insetsInfo.touchableRegion);
-            }
+            // Always have nav buttons be touchable
+            mControllers.navbarButtonsViewController.addVisibleButtonsRegion(
+                    mTaskbarDragLayer, insetsInfo.touchableRegion);
 
             if (mTaskbarDragLayer.getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
                 // Let touches pass through us.
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 5b9e214..d4c94db 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -366,8 +366,8 @@
      * device is considered in multiWindowMode and things like insets and stuff change
      * and calculations have to be adjusted in the animations for that
      */
-    public static void composeRecentsSplitLaunchAnimator(@NonNull TaskView initialView,
-            @NonNull TaskView v, @NonNull TransitionInfo transitionInfo,
+    public static void composeRecentsSplitLaunchAnimator(@NonNull Task initalTask,
+            @NonNull Task secondTask, @NonNull TransitionInfo transitionInfo,
             SurfaceControl.Transaction t, @NonNull Runnable finishCallback) {
 
         final TransitionInfo.Change[] splitRoots = new TransitionInfo.Change[2];
@@ -377,7 +377,7 @@
             final int mode = change.getMode();
             // Find the target tasks' root tasks since those are the split stages that need to
             // be animated (the tasks themselves are children and thus inherit animation).
-            if (taskId == initialView.getTask().key.id || taskId == v.getTask().key.id) {
+            if (taskId == initalTask.key.id || taskId == secondTask.key.id) {
                 if (!(mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
                     throw new IllegalStateException(
                             "Expected task to be showing, but it is " + mode);
@@ -386,7 +386,7 @@
                     throw new IllegalStateException("Initiating multi-split launch but the split"
                             + "root of " + taskId + " is already visible or has broken hierarchy.");
                 }
-                splitRoots[taskId == initialView.getTask().key.id ? 0 : 1] =
+                splitRoots[taskId == initalTask.key.id ? 0 : 1] =
                         transitionInfo.getChange(change.getParent());
             }
         }
@@ -406,8 +406,8 @@
     }
 
     /** Legacy version (until shell transitions are enabled) */
-    public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull TaskView initialView,
-            @NonNull TaskView v, @NonNull RemoteAnimationTargetCompat[] appTargets,
+    public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull Task initialTask,
+            @NonNull Task secondTask, @NonNull RemoteAnimationTargetCompat[] appTargets,
             @NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
             @NonNull RemoteAnimationTargetCompat[] nonAppTargets,
             @NonNull Runnable finishCallback) {
@@ -416,12 +416,12 @@
         for (int i = 0; i < appTargets.length; ++i) {
             final int taskId = appTargets[i].taskInfo != null ? appTargets[i].taskInfo.taskId : -1;
             final int mode = appTargets[i].mode;
-            if (taskId == initialView.getTask().key.id || taskId == v.getTask().key.id) {
+            if (taskId == initialTask.key.id || taskId == secondTask.key.id) {
                 if (mode != MODE_OPENING) {
                     throw new IllegalStateException(
                             "Expected task to be opening, but it is " + mode);
                 }
-                splitRoots[taskId == initialView.getTask().key.id ? 0 : 1] = i;
+                splitRoots[taskId == initialTask.key.id ? 0 : 1] = i;
             }
         }
 
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index cbc5584..ac5f5d8 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -33,7 +33,7 @@
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskAnimationManager;
 import com.android.quickstep.TaskViewUtils;
-import com.android.quickstep.views.TaskView;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
 import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -47,23 +47,21 @@
 public class SplitSelectStateController {
 
     private final SystemUiProxy mSystemUiProxy;
-    private TaskView mInitialTaskView;
-    private TaskView mSecondTaskView;
     private @StagePosition int mStagePosition;
+    private Task mInitialTask;
+    private Task mSecondTask;
     private Rect mInitialBounds;
-    private final Handler mHandler;
 
     public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy) {
         mSystemUiProxy = systemUiProxy;
-        mHandler = handler;
     }
 
     /**
      * To be called after first task selected
      */
-    public void setInitialTaskSelect(TaskView taskView, @StagePosition int stagePosition,
+    public void setInitialTaskSelect(Task taskView, @StagePosition int stagePosition,
             Rect initialBounds) {
-        mInitialTaskView = taskView;
+        mInitialTask = taskView;
         mStagePosition = stagePosition;
         mInitialBounds = initialBounds;
     }
@@ -71,21 +69,28 @@
     /**
      * To be called after second task selected
      */
-    public void setSecondTaskId(TaskView taskView) {
-        mSecondTaskView = taskView;
+    public void setSecondTaskId(Task taskView) {
+        mSecondTask = taskView;
+        launchTasks(mInitialTask, mSecondTask, mStagePosition);
+    }
+
+    /**
+     * @param stagePosition representing location of task1
+     */
+    public void launchTasks(Task task1, Task task2, @StagePosition int stagePosition) {
         // Assume initial task is for top/left part of screen
-        final int[] taskIds = mStagePosition == STAGE_POSITION_TOP_OR_LEFT
-                ? new int[]{mInitialTaskView.getTask().key.id, taskView.getTask().key.id}
-                : new int[]{taskView.getTask().key.id, mInitialTaskView.getTask().key.id};
+        final int[] taskIds = stagePosition == STAGE_POSITION_TOP_OR_LEFT
+                ? new int[]{task1.key.id, task2.key.id}
+                : new int[]{task2.key.id, task1.key.id};
         if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
             RemoteSplitLaunchTransitionRunner animationRunner =
-                    new RemoteSplitLaunchTransitionRunner(mInitialTaskView, taskView);
+                    new RemoteSplitLaunchTransitionRunner(task1, task2);
             mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1],
                     null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
                     new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR));
         } else {
             RemoteSplitLaunchAnimationRunner animationRunner =
-                    new RemoteSplitLaunchAnimationRunner(mInitialTaskView, taskView);
+                    new RemoteSplitLaunchAnimationRunner(task1, task2);
             final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
                     RemoteAnimationAdapterCompat.wrapRemoteAnimationRunner(animationRunner),
                     300, 150,
@@ -105,19 +110,19 @@
      */
     private class RemoteSplitLaunchTransitionRunner implements RemoteTransitionRunner {
 
-        private final TaskView mInitialTaskView;
-        private final TaskView mTaskView;
+        private final Task mInitialTask;
+        private final Task mSecondTask;
 
-        RemoteSplitLaunchTransitionRunner(TaskView initialTaskView, TaskView taskView) {
-            mInitialTaskView = initialTaskView;
-            mTaskView = taskView;
+        RemoteSplitLaunchTransitionRunner(Task initialTask, Task secondTask) {
+            mInitialTask = initialTask;
+            mSecondTask = secondTask;
         }
 
         @Override
         public void startAnimation(IBinder transition, TransitionInfo info,
                 SurfaceControl.Transaction t, Runnable finishCallback) {
-            TaskViewUtils.composeRecentsSplitLaunchAnimator(mInitialTaskView, mTaskView,
-                    info, t, finishCallback);
+            TaskViewUtils.composeRecentsSplitLaunchAnimator(mInitialTask,
+                    mSecondTask, info, t, finishCallback);
             // After successful launch, call resetState
             resetState();
         }
@@ -129,20 +134,20 @@
      */
     private class RemoteSplitLaunchAnimationRunner implements RemoteAnimationRunnerCompat {
 
-        private final TaskView mInitialTaskView;
-        private final TaskView mTaskView;
+        private final Task mInitialTask;
+        private final Task mSecondTask;
 
-        RemoteSplitLaunchAnimationRunner(TaskView initialTaskView, TaskView taskView) {
-            mInitialTaskView = initialTaskView;
-            mTaskView = taskView;
+        RemoteSplitLaunchAnimationRunner(Task initialTask, Task secondTask) {
+            mInitialTask = initialTask;
+            mSecondTask = secondTask;
         }
 
         @Override
         public void onAnimationStart(int transit, RemoteAnimationTargetCompat[] apps,
                 RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps,
                 Runnable finishedCallback) {
-            TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(mInitialTaskView, mTaskView, apps,
-                    wallpapers, nonApps, finishedCallback);
+            TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(mInitialTask,
+                    mSecondTask, apps, wallpapers, nonApps, finishedCallback);
             // After successful launch, call resetState
             resetState();
         }
@@ -157,8 +162,8 @@
      * To be called if split select was cancelled
      */
     public void resetState() {
-        mInitialTaskView = null;
-        mSecondTaskView = null;
+        mInitialTask = null;
+        mSecondTask = null;
         mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
         mInitialBounds = null;
     }
@@ -168,7 +173,7 @@
      *         chosen
      */
     public boolean isSplitSelectActive() {
-        return mInitialTaskView != null && mSecondTaskView == null;
+        return mInitialTask != null && mSecondTask == null;
     }
 
     public Rect getInitialBounds() {
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 1bc7c75..e1e1c65 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -4,6 +4,7 @@
 import android.util.AttributeSet;
 
 import com.android.launcher3.R;
+import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.TaskThumbnailCache;
@@ -95,6 +96,13 @@
     }
 
     @Override
+    public RunnableList launchTaskAnimated() {
+        getRecentsView().getSplitPlaceholder().launchTasks(mTask, mSecondaryTask,
+                SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT);
+        return null;
+    }
+
+    @Override
     public void onRecycle() {
         super.onRecycle();
         mSnapshotView2.setThumbnail(mSecondaryTask, null);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 18387dc..810ecce 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -3568,7 +3568,8 @@
         mSplitHiddenTaskView = taskView;
         Rect initialBounds = new Rect(taskView.getLeft(), taskView.getTop(), taskView.getRight(),
                 taskView.getBottom());
-        mSplitSelectStateController.setInitialTaskSelect(taskView, stagePosition, initialBounds);
+        mSplitSelectStateController.setInitialTaskSelect(taskView.getTask(),
+                stagePosition, initialBounds);
         mSplitHiddenTaskViewIndex = indexOfChild(taskView);
         if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
             finishRecentsAnimation(true, null);
@@ -3609,7 +3610,7 @@
                 secondTaskEndingBounds, taskView.getThumbnail(),
                 true /*fadeWithThumbnail*/);
         pendingAnimation.addEndListener(aBoolean -> {
-            mSplitSelectStateController.setSecondTaskId(taskView);
+            mSplitSelectStateController.setSecondTaskId(taskView.getTask());
             resetFromSplitSelectionState();
         });
         mSecondSplitHiddenTaskView = taskView;
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index fae55cc..f9a9997 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -15,6 +15,7 @@
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 
+import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -66,15 +67,18 @@
         onError(mDevice, description, e);
     }
 
+    static File diagFile(Description description, String prefix, String ext) {
+        return new File(getInstrumentation().getTargetContext().getFilesDir(),
+                prefix + "-" + description.getTestClass().getSimpleName() + "."
+                        + description.getMethodName() + "." + ext);
+    }
+
     public static void onError(UiDevice device, Description description, Throwable e) {
         Log.d("b/196820244", "onError 1");
         if (device == null) return;
         Log.d("b/196820244", "onError 2");
-        final File parentFile = getInstrumentation().getTargetContext().getFilesDir();
-        final File sceenshot = new File(parentFile,
-                "TestScreenshot-" + description.getMethodName() + ".png");
-        final File hierarchy = new File(parentFile,
-                "Hierarchy-" + description.getMethodName() + ".zip");
+        final File sceenshot = diagFile(description, "TestScreenshot", "png");
+        final File hierarchy = diagFile(description, "Hierarchy", "zip");
 
         // Dump window hierarchy
         try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(hierarchy))) {
@@ -97,13 +101,13 @@
         device.takeScreenshot(sceenshot);
 
         // Dump accessibility hierarchy
-        final File accessibilityHierarchyFile = new File(parentFile,
-                "AccessibilityHierarchy-" + description.getMethodName() + ".uix");
         try {
-            device.dumpWindowHierarchy(accessibilityHierarchyFile);
+            device.dumpWindowHierarchy(diagFile(description, "AccessibilityHierarchy", "uix"));
         } catch (IOException ex) {
             Log.e(TAG, "Failed to save accessibility hierarchy", ex);
         }
+
+        dumpCommand("logcat -d -s TestRunner", diagFile(description, "FilteredLogcat", "txt"));
     }
 
     private static void dumpStringCommand(String cmd, OutputStream out) throws IOException {
@@ -111,6 +115,14 @@
         dumpCommand(cmd, out);
     }
 
+    private static void dumpCommand(String cmd, File out) {
+        try (BufferedOutputStream buffered = new BufferedOutputStream(
+                new FileOutputStream(out))) {
+            dumpCommand(cmd, buffered);
+        } catch (IOException ex) {
+        }
+    }
+
     private static void dumpCommand(String cmd, OutputStream out) throws IOException {
         try (AutoCloseInputStream in = new AutoCloseInputStream(getInstrumentation()
                 .getUiAutomation().executeShellCommand(cmd))) {