diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index c80818abbb..b8ce818da0 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -349,7 +349,7 @@ public abstract class BaseQuickstepLauncher extends Launcher mActionsView = findViewById(R.id.overview_actions_view); RecentsView overviewPanel = (RecentsView) getOverviewPanel(); SplitSelectStateController controller = - new SplitSelectStateController(SystemUiProxy.INSTANCE.get(this)); + new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this)); overviewPanel.init(mActionsView, controller); mActionsView.setDp(getDeviceProfile()); mActionsView.updateVerticalMargin(SysUINavigationMode.getMode(this)); diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java index cc6cfd72f7..03e2395029 100644 --- a/quickstep/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/src/com/android/quickstep/RecentsActivity.java @@ -122,7 +122,7 @@ public final class RecentsActivity extends StatefulActivity { SYSUI_PROGRESS.set(getRootView().getSysUiScrim(), 0f); SplitSelectStateController controller = - new SplitSelectStateController(SystemUiProxy.INSTANCE.get(this)); + new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this)); mDragLayer.recreateControllers(); mFallbackRecentsView.init(mActionsView, controller); } diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java index 23dc913ce1..37d88ae022 100644 --- a/quickstep/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java @@ -35,6 +35,7 @@ import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLAT import static com.android.launcher3.anim.Interpolators.clampToProgress; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.statehandlers.DepthController.DEPTH; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING; @@ -42,6 +43,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; import android.annotation.TargetApi; import android.content.ComponentName; import android.content.Context; @@ -79,6 +81,8 @@ import com.android.systemui.shared.system.InteractionJankMonitorWrapper; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; +import java.util.ArrayList; + /** * Utility class for helpful methods related to {@link TaskView} objects and their tasks. */ @@ -427,34 +431,64 @@ public final class TaskViewUtils { @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, @NonNull RemoteAnimationTargetCompat[] nonAppTargets, @NonNull Runnable finishCallback) { + final ArrayList openingTargets = new ArrayList<>(); + final ArrayList closingTargets = new ArrayList<>(); - 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 == 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 == initialTask.key.id ? 0 : 1] = i; + for (RemoteAnimationTargetCompat appTarget : appTargets) { + final int taskId = appTarget.taskInfo != null ? appTarget.taskInfo.taskId : -1; + final int mode = appTarget.mode; + final SurfaceControl leash = appTarget.leash.getSurfaceControl(); + if (leash == null) { + continue; + } + + if (mode == MODE_OPENING) { + openingTargets.add(leash); + } else if (taskId == initialTask.key.id || taskId == secondTask.key.id) { + throw new IllegalStateException("Expected task to be opening, but it is " + mode); + } else if (mode == MODE_CLOSING) { + closingTargets.add(leash); } } - SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - - // 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); + for (int i = 0; i < nonAppTargets.length; ++i) { + final SurfaceControl leash = appTargets[i].leash.getSurfaceControl(); + if (nonAppTargets[i].windowType == TYPE_DOCK_DIVIDER && leash != null) { + openingTargets.add(leash); + } } - // This contains the initial state (before animation), so apply this at the beginning of - // the animation. - t.apply(); + final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f); + animator.addUpdateListener(valueAnimator -> { + float progress = valueAnimator.getAnimatedFraction(); + for (SurfaceControl leash: openingTargets) { + t.setAlpha(leash, progress); + } + for (SurfaceControl leash: closingTargets) { + t.setAlpha(leash, 1 - progress); + } + t.apply(); + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + for (SurfaceControl leash: openingTargets) { + t.show(leash).setAlpha(leash, 0.0f); + } + t.apply(); + } - // Once there is an animation, this should be called AFTER the animation completes. - finishCallback.run(); + @Override + public void onAnimationEnd(Animator animation) { + for (SurfaceControl leash: closingTargets) { + t.hide(leash); + } + super.onAnimationEnd(animation); + finishCallback.run(); + } + }); + animator.start(); } 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 3069504943..e9a695d328 100644 --- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java +++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java @@ -16,17 +16,20 @@ package com.android.quickstep.util; +import static com.android.launcher3.Utilities.postAsyncCallback; 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.app.ActivityThread; import android.graphics.Rect; +import android.os.Handler; import android.os.IBinder; import android.view.RemoteAnimationAdapter; import android.view.SurfaceControl; import android.window.TransitionInfo; +import com.android.launcher3.Utilities; import com.android.launcher3.util.SplitConfigurationOptions; import com.android.launcher3.util.SplitConfigurationOptions.StagePosition; import com.android.quickstep.SystemUiProxy; @@ -47,13 +50,15 @@ import java.util.function.Consumer; */ public class SplitSelectStateController { + private final Handler mHandler; private final SystemUiProxy mSystemUiProxy; private @StagePosition int mStagePosition; private Task mInitialTask; private Task mSecondTask; private Rect mInitialBounds; - public SplitSelectStateController(SystemUiProxy systemUiProxy) { + public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy) { + mHandler = handler; mSystemUiProxy = systemUiProxy; } @@ -70,9 +75,9 @@ public class SplitSelectStateController { /** * To be called after second task selected */ - public void setSecondTaskId(Task taskView) { + public void setSecondTaskId(Task taskView, Consumer callback) { mSecondTask = taskView; - launchTasks(mInitialTask, mSecondTask, mStagePosition, null /*callback*/); + launchTasks(mInitialTask, mSecondTask, mStagePosition, callback); } /** @@ -151,22 +156,27 @@ public class SplitSelectStateController { public void onAnimationStart(int transit, RemoteAnimationTargetCompat[] apps, RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps, Runnable finishedCallback) { - TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(mInitialTask, - mSecondTask, apps, wallpapers, nonApps, () -> { - finishedCallback.run(); - if (mSuccessCallback != null) { - mSuccessCallback.accept(true); - } - }); + postAsyncCallback(mHandler, + () -> TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(mInitialTask, + mSecondTask, apps, wallpapers, nonApps, () -> { + finishedCallback.run(); + if (mSuccessCallback != null) { + mSuccessCallback.accept(true); + } + })); + // After successful launch, call resetState resetState(); } @Override public void onAnimationCancelled() { - if (mSuccessCallback != null) { - mSuccessCallback.accept(false); - } + postAsyncCallback(mHandler, () -> { + if (mSuccessCallback != null) { + mSuccessCallback.accept(false); + } + }); + resetState(); } } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index cb8e7f75aa..5794396a14 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -3836,10 +3836,9 @@ public abstract class RecentsView { - mSplitSelectStateController.setSecondTaskId(taskView.getTask()); - resetFromSplitSelectionState(); - }); + pendingAnimation.addEndListener(aBoolean -> + mSplitSelectStateController.setSecondTaskId(taskView.getTask(), + aBoolean1 -> RecentsView.this.resetFromSplitSelectionState())); mSecondSplitHiddenTaskView = taskView; taskView.setVisibility(INVISIBLE); pendingAnimation.buildAnim().start();