Merge "Correct # of cells estimation that can fit horizontally in widgets picker" into sc-v2-dev
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 090fd01..6226fb0 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -33,6 +33,7 @@
 import android.os.UserHandle;
 import android.util.Log;
 import android.view.MotionEvent;
+import android.view.RemoteAnimationAdapter;
 import android.view.SurfaceControl;
 
 import com.android.launcher3.util.MainThreadInitializedObject;
@@ -562,6 +563,22 @@
         }
     }
 
+    /**
+     * Start multiple tasks in split-screen simultaneously.
+     */
+    public void startTasksWithLegacyTransition(int mainTaskId, Bundle mainOptions, int sideTaskId,
+            Bundle sideOptions, @SplitConfigurationOptions.StagePosition int sidePosition,
+            RemoteAnimationAdapter adapter) {
+        if (mSystemUiProxy != null) {
+            try {
+                mSplitScreen.startTasksWithLegacyTransition(mainTaskId, mainOptions, sideTaskId,
+                        sideOptions, sidePosition, adapter);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call startTasksWithLegacyTransition");
+            }
+        }
+    }
+
     public void startShortcut(String packageName, String shortcutId, int stage, int position,
             Bundle options, UserHandle user) {
         if (mSplitScreen != null) {
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 37fda73..a85a24d 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -405,77 +405,39 @@
     }
 
     /** Legacy version (until shell transitions are enabled) */
-    public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull AnimatorSet anim,
+    public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull TaskView initialView,
             @NonNull TaskView v, @NonNull RemoteAnimationTargetCompat[] appTargets,
             @NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
-            @NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing,
-            @NonNull StateManager stateManager, @NonNull DepthController depthController,
-            int targetStage) {
-        PendingAnimation out = new PendingAnimation(RECENTS_LAUNCH_DURATION);
-        boolean isRunningTask = v.isRunningTask();
-        TransformParams params = null;
-        TaskViewSimulator tvs = null;
-        RecentsView recentsView = v.getRecentsView();
-        if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask) {
-            params = recentsView.getLiveTileParams();
-            tvs = recentsView.getLiveTileTaskViewSimulator();
+            @NonNull RemoteAnimationTargetCompat[] nonAppTargets,
+            @NonNull Runnable finishCallback) {
+
+        final int[] splitRoots = new int[2];
+        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 (mode != MODE_OPENING) {
+                    throw new IllegalStateException(
+                            "Expected task to be opening, but it is " + mode);
+                }
+                splitRoots[taskId == initialView.getTask().key.id ? 0 : 1] = i;
+            }
         }
 
-        boolean inLiveTileMode =
-                ENABLE_QUICKSTEP_LIVE_TILE.get() && recentsView.getRunningTaskIndex() != -1;
-        final RemoteAnimationTargets targets =
-                new RemoteAnimationTargets(appTargets, wallpaperTargets, nonAppTargets,
-                        inLiveTileMode ? MODE_CLOSING : MODE_OPENING);
+        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
 
-        if (params == null) {
-            SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v);
-            targets.addReleaseCheck(applier);
-
-            params = new TransformParams()
-                    .setSyncTransactionApplier(applier)
-                    .setTargetSet(targets);
+        // This is where we should animate the split roots. For now, though, just make them visible.
+        for (int i = 0; i < 2; ++i) {
+            t.show(appTargets[splitRoots[i]].leash.getSurfaceControl());
+            t.setAlpha(appTargets[splitRoots[i]].leash.getSurfaceControl(), 1.f);
         }
 
-        Rect crop = new Rect();
-        Context context = v.getContext();
-        DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
-        if (tvs == null && targets.apps.length > 0) {
-            tvs = new TaskViewSimulator(recentsView.getContext(), recentsView.getSizeStrategy());
-            tvs.setDp(dp);
+        // This contains the initial state (before animation), so apply this at the beginning of
+        // the animation.
+        t.apply();
 
-            // RecentsView never updates the display rotation until swipe-up so the value may
-            // be stale. Use the display value instead.
-            int displayRotation = DisplayController.INSTANCE.get(recentsView.getContext())
-                    .getInfo().rotation;
-            tvs.getOrientationState().update(displayRotation, displayRotation);
-
-            tvs.setPreview(targets.apps[targets.apps.length - 1]);
-            tvs.fullScreenProgress.value = 0;
-            tvs.recentsViewScale.value = 1;
-//            tvs.setScroll(startScroll);
-
-            // Fade in the task during the initial 20% of the animation
-            out.addFloat(params, TransformParams.TARGET_ALPHA, 0, 1,
-                    clampToProgress(LINEAR, 0, 0.2f));
-        }
-
-        TaskViewSimulator topMostSimulator = null;
-
-        if (tvs != null) {
-            out.setFloat(tvs.fullScreenProgress,
-                    AnimatedFloat.VALUE, 1, TOUCH_RESPONSE_INTERPOLATOR);
-            out.setFloat(tvs.recentsViewScale,
-                    AnimatedFloat.VALUE, tvs.getFullScreenScale(), TOUCH_RESPONSE_INTERPOLATOR);
-            out.setFloat(tvs.recentsViewScroll,
-                    AnimatedFloat.VALUE, 0, TOUCH_RESPONSE_INTERPOLATOR);
-
-            TaskViewSimulator finalTsv = tvs;
-            TransformParams finalParams = params;
-            out.addOnFrameCallback(() -> finalTsv.apply(finalParams));
-            topMostSimulator = tvs;
-        }
-
-        anim.play(out.buildAnim());
+        // Once there is an animation, this should be called AFTER the animation completes.
+        finishCallback.run();
     }
 
     public static void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index a147b68..2351a4e 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -22,33 +22,26 @@
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
 
-import android.animation.AnimatorSet;
-import android.app.ActivityOptions;
+import android.app.ActivityThread;
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
-import android.util.Pair;
 import android.view.Gravity;
+import android.view.RemoteAnimationAdapter;
 import android.view.SurfaceControl;
 import android.window.TransitionInfo;
 
 import androidx.annotation.Nullable;
 
-import com.android.launcher3.BaseActivity;
-import com.android.launcher3.BaseQuickstepLauncher;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.InsettableFrameLayout;
-import com.android.launcher3.LauncherAnimationRunner;
-import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory;
 import com.android.launcher3.R;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 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.system.ActivityOptionsCompat;
 import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
 import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -92,37 +85,27 @@
                     ? new int[]{mInitialTaskView.getTask().key.id, taskView.getTask().key.id}
                     : new int[]{taskView.getTask().key.id, mInitialTaskView.getTask().key.id};
 
-            RemoteSplitLaunchAnimationRunner animationRunner =
-                    new RemoteSplitLaunchAnimationRunner(mInitialTaskView, taskView);
+            RemoteSplitLaunchTransitionRunner animationRunner =
+                    new RemoteSplitLaunchTransitionRunner(mInitialTaskView, taskView);
             mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1],
                     null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
                     new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR));
-            return;
+        } else {
+            // Assume initial task is for top/left part of screen
+            final int[] taskIds = mInitialPosition.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};
+
+            RemoteSplitLaunchAnimationRunner animationRunner =
+                    new RemoteSplitLaunchAnimationRunner(mInitialTaskView, taskView);
+            final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
+                    RemoteAnimationAdapterCompat.wrapRemoteAnimationRunner(animationRunner),
+                    300, 150,
+                    ActivityThread.currentActivityThread().getApplicationThread());
+
+            mSystemUiProxy.startTasksWithLegacyTransition(taskIds[0], null /* mainOptions */,
+                    taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, adapter);
         }
-        // Assume initial mInitialTaskId is for top/left part of screen
-        RemoteAnimationFactory initialSplitRunnerWrapped =  new SplitLaunchAnimationRunner(
-                mInitialTaskView, 0);
-        RemoteAnimationFactory secondarySplitRunnerWrapped =  new SplitLaunchAnimationRunner(
-                taskView, 1);
-        RemoteAnimationRunnerCompat initialSplitRunner = new LauncherAnimationRunner(
-                new Handler(Looper.getMainLooper()), initialSplitRunnerWrapped,
-                true /* startAtFrontOfQueue */);
-        RemoteAnimationRunnerCompat secondarySplitRunner = new LauncherAnimationRunner(
-                new Handler(Looper.getMainLooper()), secondarySplitRunnerWrapped,
-                true /* startAtFrontOfQueue */);
-        ActivityOptions initialOptions = ActivityOptionsCompat.makeRemoteAnimation(
-                new RemoteAnimationAdapterCompat(initialSplitRunner, 300, 150));
-        ActivityOptions secondaryOptions = ActivityOptionsCompat.makeRemoteAnimation(
-                new RemoteAnimationAdapterCompat(secondarySplitRunner, 300, 150));
-        mSystemUiProxy.startTask(mInitialTaskView.getTask().key.id, mInitialPosition.mStageType,
-                mInitialPosition.mStagePosition,
-                /*null*/ initialOptions.toBundle());
-        Pair<Integer, Integer> compliment = getComplimentaryStageAndPosition(mInitialPosition);
-        mSystemUiProxy.startTask(taskView.getTask().key.id, compliment.first,
-                compliment.second,
-                /*null*/ secondaryOptions.toBundle());
-        // After successful launch, call resetState
-        resetState();
     }
 
     /**
@@ -153,12 +136,12 @@
     /**
      * Requires Shell Transitions
      */
-    private class RemoteSplitLaunchAnimationRunner implements RemoteTransitionRunner {
+    private class RemoteSplitLaunchTransitionRunner implements RemoteTransitionRunner {
 
         private final TaskView mInitialTaskView;
         private final TaskView mTaskView;
 
-        RemoteSplitLaunchAnimationRunner(TaskView initialTaskView, TaskView taskView) {
+        RemoteSplitLaunchTransitionRunner(TaskView initialTaskView, TaskView taskView) {
             mInitialTaskView = initialTaskView;
             mTaskView = taskView;
         }
@@ -175,48 +158,34 @@
 
     /**
      * LEGACY
-     * @return the opposite stage and position from the {@param position} provided as first and
-     *         second object, respectively
-     * Ex. If position is has stage = Main and position = Top/Left, this will return
-     * Pair(stage=Side, position=Bottom/Left)
-     */
-    private Pair<Integer, Integer> getComplimentaryStageAndPosition(SplitPositionOption position) {
-        // Right now this is as simple as flipping between 0 and 1
-        int complimentStageType = position.mStageType ^ 1;
-        int complimentStagePosition = position.mStagePosition ^ 1;
-        return new Pair<>(complimentStageType, complimentStagePosition);
-    }
-
-    /**
-     * LEGACY
      * Remote animation runner for animation to launch an app.
      */
-    private class SplitLaunchAnimationRunner implements RemoteAnimationFactory {
+    private class RemoteSplitLaunchAnimationRunner implements RemoteAnimationRunnerCompat {
 
-        private final TaskView mV;
-        private final int mTargetState;
+        private final TaskView mInitialTaskView;
+        private final TaskView mTaskView;
 
-        SplitLaunchAnimationRunner(TaskView v, int targetState) {
-            mV = v;
-            mTargetState = targetState;
+        RemoteSplitLaunchAnimationRunner(TaskView initialTaskView, TaskView taskView) {
+            mInitialTaskView = initialTaskView;
+            mTaskView = taskView;
         }
 
         @Override
-        public void onCreateAnimation(int transit,
-                RemoteAnimationTargetCompat[] appTargets,
-                RemoteAnimationTargetCompat[] wallpaperTargets,
-                RemoteAnimationTargetCompat[] nonAppTargets,
-                LauncherAnimationRunner.AnimationResult result) {
-            AnimatorSet anim = new AnimatorSet();
-            BaseQuickstepLauncher activity = BaseActivity.fromContext(mV.getContext());
-            TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(anim, mV,
-                    appTargets, wallpaperTargets, nonAppTargets, true, activity.getStateManager(),
-                    activity.getDepthController(), mTargetState);
-            result.setAnimation(anim, activity);
+        public void onAnimationStart(int transit, RemoteAnimationTargetCompat[] apps,
+                RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps,
+                Runnable finishedCallback) {
+            TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(mInitialTaskView, mTaskView, apps,
+                    wallpapers, nonApps, finishedCallback);
+            // After successful launch, call resetState
+            resetState();
+        }
+
+        @Override
+        public void onAnimationCancelled() {
+            resetState();
         }
     }
 
-
     /**
      * To be called if split select was cancelled
      */
diff --git a/robolectric_tests/src/com/android/launcher3/widget/CachingWidgetPreviewLoaderTest.java b/robolectric_tests/src/com/android/launcher3/widget/CachingWidgetPreviewLoaderTest.java
index c18e26c..1090d1e 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/CachingWidgetPreviewLoaderTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/CachingWidgetPreviewLoaderTest.java
@@ -52,15 +52,15 @@
 
 @RunWith(RobolectricTestRunner.class)
 public class CachingWidgetPreviewLoaderTest {
-    private static final Size SIZE_10_10 = new Size(10, 10);
-    private static final Size SIZE_20_20 = new Size(20, 20);
+    private final Size SIZE_10_10 = new Size(10, 10);
+    private final Size SIZE_20_20 = new Size(20, 20);
     private static final String TEST_PACKAGE = "com.example.test";
-    private static final ComponentName TEST_PROVIDER =
+    private final ComponentName TEST_PROVIDER =
             new ComponentName(TEST_PACKAGE, ".WidgetProvider");
-    private static final ComponentName TEST_PROVIDER2 =
+    private final ComponentName TEST_PROVIDER2 =
             new ComponentName(TEST_PACKAGE, ".WidgetProvider2");
-    private static final Bitmap BITMAP = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
-    private static final Bitmap BITMAP2 = Bitmap.createBitmap(20, 20, Bitmap.Config.ARGB_8888);
+    private final Bitmap BITMAP = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
+    private final Bitmap BITMAP2 = Bitmap.createBitmap(20, 20, Bitmap.Config.ARGB_8888);
 
 
     @Mock private CancellationSignal mCancellationSignal;