From d3ceb3dc88e67214828a4a71ad5ff56e1d887910 Mon Sep 17 00:00:00 2001 From: Jerry Chang Date: Mon, 13 Sep 2021 12:08:07 +0800 Subject: [PATCH] Reset floating split task view after remote animation finished Move reseting floating task view for entering split after remote animation finished to prevent the floating task view disappear before opening split task view being visible and causing flicker. Bug: 199377815 Test: Manual check the flicker disappear Change-Id: I4a864335972842570c61291a7a0c423edeb74578 --- .../launcher3/BaseQuickstepLauncher.java | 2 +- .../android/quickstep/RecentsActivity.java | 2 +- .../com/android/quickstep/TaskViewUtils.java | 76 ++++++++++++++----- .../util/SplitSelectStateController.java | 36 +++++---- .../android/quickstep/views/RecentsView.java | 7 +- 5 files changed, 83 insertions(+), 40 deletions(-) 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();