From 1abc73c587b9e6ab921a09ddd5587a01e6710dea Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Tue, 29 Jun 2021 19:07:05 -0700 Subject: [PATCH] Hook up split-launch to legacy transition system Adds legacy versions of the animation logic. Bug: 192279476 Test: use SPLIT_SELECT to launch 2 apps in split and observe Change-Id: I5cbe7416819ba88d8c081fb413177fadac5b815d --- .../com/android/quickstep/SystemUiProxy.java | 17 +++ .../com/android/quickstep/TaskViewUtils.java | 88 ++++---------- .../util/SplitSelectStateController.java | 109 +++++++----------- 3 files changed, 81 insertions(+), 133 deletions(-) diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index 090fd015a4..6226fb0dc0 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -33,6 +33,7 @@ import android.os.RemoteException; 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 @@ public class SystemUiProxy implements ISystemUiProxy, } } + /** + * 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 37fda73d44..a85a24dcd9 100644 --- a/quickstep/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java @@ -405,77 +405,39 @@ public final class TaskViewUtils { } /** 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 a147b6808c..2351a4e164 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.Executors.MAIN_EXECUTOR; 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 @@ public class SplitSelectStateController { ? 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 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 @@ public class SplitSelectStateController { /** * 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; } @@ -173,50 +156,36 @@ public class SplitSelectStateController { } } - /** - * 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 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 */