From d7d381caabc3f87ab9ea51b391cb5a28e17b033e Mon Sep 17 00:00:00 2001 From: Tony Huang Date: Thu, 27 Oct 2022 16:30:48 +0800 Subject: [PATCH] Reduce switch split flicker on protrait split Due to insets for tasks would be changed when switch split on protrait mode, it lead to some flicker. Attach screenshots before switch and fading out after switch animation finished to reduce flicker. Also update animation algorithm to reduce flicker occured when top to bottom case. Fix: 240517067 Test: manual Test: pass existing tests Change-Id: I66991b40b2ab8f410abcb800e9ca6e80222faa8c --- .../wm/shell/common/split/SplitLayout.java | 28 ++++++-------- .../shell/splitscreen/StageCoordinator.java | 38 +++++++++++++++++-- 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index c2ad1a98d1670..5b7d141591ea8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -69,6 +69,7 @@ import com.android.wm.shell.common.InteractionJankMonitorUtils; import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition; import java.io.PrintWriter; +import java.util.function.Consumer; /** * Records and handles layout of splits. Helps to calculate proper bounds when configuration or @@ -599,7 +600,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange /** Swich both surface position with animation. */ public void splitSwitching(SurfaceControl.Transaction t, SurfaceControl leash1, - SurfaceControl leash2, Runnable finishCallback) { + SurfaceControl leash2, Consumer finishCallback) { final boolean isLandscape = isLandscape(); final Rect insets = getDisplayInsets(mContext); insets.set(isLandscape ? insets.left : 0, isLandscape ? 0 : insets.top, @@ -617,18 +618,13 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange distBounds1.offset(-mRootBounds.left, -mRootBounds.top); distBounds2.offset(-mRootBounds.left, -mRootBounds.top); distDividerBounds.offset(-mRootBounds.left, -mRootBounds.top); - // DO NOT move to insets area for smooth animation. - distBounds1.set(distBounds1.left, distBounds1.top, - distBounds1.right - insets.right, distBounds1.bottom - insets.bottom); - distBounds2.set(distBounds2.left + insets.left, distBounds2.top + insets.top, - distBounds2.right, distBounds2.bottom); ValueAnimator animator1 = moveSurface(t, leash1, getRefBounds1(), distBounds1, - false /* alignStart */); + -insets.left, -insets.top); ValueAnimator animator2 = moveSurface(t, leash2, getRefBounds2(), distBounds2, - true /* alignStart */); + insets.left, insets.top); ValueAnimator animator3 = moveSurface(t, getDividerLeash(), getRefDividerBounds(), - distDividerBounds, true /* alignStart */); + distDividerBounds, 0 /* offsetX */, 0 /* offsetY */); AnimatorSet set = new AnimatorSet(); set.playTogether(animator1, animator2, animator3); @@ -638,14 +634,14 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange public void onAnimationEnd(Animator animation) { mDividePosition = dividerPos; updateBounds(mDividePosition); - finishCallback.run(); + finishCallback.accept(insets); } }); set.start(); } private ValueAnimator moveSurface(SurfaceControl.Transaction t, SurfaceControl leash, - Rect start, Rect end, boolean alignStart) { + Rect start, Rect end, float offsetX, float offsetY) { Rect tempStart = new Rect(start); Rect tempEnd = new Rect(end); final float diffX = tempEnd.left - tempStart.left; @@ -661,15 +657,15 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange final float distY = tempStart.top + scale * diffY; final int width = (int) (tempStart.width() + scale * diffWidth); final int height = (int) (tempStart.height() + scale * diffHeight); - if (alignStart) { + if (offsetX == 0 && offsetY == 0) { t.setPosition(leash, distX, distY); t.setWindowCrop(leash, width, height); } else { - final int offsetX = width - tempStart.width(); - final int offsetY = height - tempStart.height(); - t.setPosition(leash, distX + offsetX, distY + offsetY); + final int diffOffsetX = (int) (scale * offsetX); + final int diffOffsetY = (int) (scale * offsetY); + t.setPosition(leash, distX + diffOffsetX, distY + diffOffsetY); mTempRect.set(0, 0, width, height); - mTempRect.offsetTo(-offsetX, -offsetY); + mTempRect.offsetTo(-diffOffsetX, -diffOffsetY); t.setCrop(leash, mTempRect); } t.apply(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index e2ac01f7b003b..1f496513c1bf5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -115,6 +115,7 @@ import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.ScreenshotUtils; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.TransactionPool; @@ -850,15 +851,44 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, void setSideStagePositionAnimated(@SplitPosition int sideStagePosition) { if (mSideStagePosition == sideStagePosition) return; SurfaceControl.Transaction t = mTransactionPool.acquire(); + mTempRect1.setEmpty(); final StageTaskListener topLeftStage = mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage; + final SurfaceControl topLeftScreenshot = ScreenshotUtils.takeScreenshot(t, + topLeftStage.mRootLeash, mTempRect1, Integer.MAX_VALUE - 1); final StageTaskListener bottomRightStage = mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage; + final SurfaceControl bottomRightScreenshot = ScreenshotUtils.takeScreenshot(t, + bottomRightStage.mRootLeash, mTempRect1, Integer.MAX_VALUE - 1); mSplitLayout.splitSwitching(t, topLeftStage.mRootLeash, bottomRightStage.mRootLeash, - () -> { - setSideStagePosition(SplitLayout.reversePosition(mSideStagePosition), - null /* wct */); - mTransactionPool.release(t); + insets -> { + WindowContainerTransaction wct = new WindowContainerTransaction(); + setSideStagePosition(SplitLayout.reversePosition(mSideStagePosition), wct); + mSyncQueue.queue(wct); + mSyncQueue.runInSync(st -> { + updateSurfaceBounds(mSplitLayout, st, false /* applyResizingOffset */); + st.setPosition(topLeftScreenshot, -insets.left, -insets.top); + st.setPosition(bottomRightScreenshot, insets.left, insets.top); + + final ValueAnimator va = ValueAnimator.ofFloat(1, 0); + va.addUpdateListener(valueAnimator-> { + final float progress = (float) valueAnimator.getAnimatedValue(); + t.setAlpha(topLeftScreenshot, progress); + t.setAlpha(bottomRightScreenshot, progress); + t.apply(); + }); + va.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd( + @androidx.annotation.NonNull Animator animation) { + t.remove(topLeftScreenshot); + t.remove(bottomRightScreenshot); + t.apply(); + mTransactionPool.release(t); + } + }); + va.start(); + }); }); }