diff options
| -rw-r--r-- | libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java | 124 | ||||
| -rw-r--r-- | libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java | 17 |
2 files changed, 124 insertions, 17 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 920dcc70ad46..c962de67a93b 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 @@ -35,6 +35,7 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.app.ActivityManager; @@ -78,6 +79,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange public static final int PARALLAX_DISMISSING = 1; public static final int PARALLAX_ALIGN_CENTER = 2; + private static final int FLING_ANIMATION_DURATION = 250; + private final int mDividerWindowWidth; private final int mDividerInsets; private final int mDividerSize; @@ -85,7 +88,9 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange private final Rect mTempRect = new Rect(); private final Rect mRootBounds = new Rect(); private final Rect mDividerBounds = new Rect(); + // Bounds1 final position should be always at top or left private final Rect mBounds1 = new Rect(); + // Bounds2 final position should be always at bottom or right private final Rect mBounds2 = new Rect(); private final Rect mWinBounds1 = new Rect(); private final Rect mWinBounds2 = new Rect(); @@ -275,28 +280,35 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange updateBounds(mDividePosition); } - /** Updates recording bounds of divider window and both of the splits. */ private void updateBounds(int position) { - mDividerBounds.set(mRootBounds); - mBounds1.set(mRootBounds); - mBounds2.set(mRootBounds); + updateBounds(position, mBounds1, mBounds2, mDividerBounds, true /* setEffectBounds */); + } + + /** Updates recording bounds of divider window and both of the splits. */ + private void updateBounds(int position, Rect bounds1, Rect bounds2, Rect dividerBounds, + boolean setEffectBounds) { + dividerBounds.set(mRootBounds); + bounds1.set(mRootBounds); + bounds2.set(mRootBounds); final boolean isLandscape = isLandscape(mRootBounds); if (isLandscape) { position += mRootBounds.left; - mDividerBounds.left = position - mDividerInsets; - mDividerBounds.right = mDividerBounds.left + mDividerWindowWidth; - mBounds1.right = position; - mBounds2.left = mBounds1.right + mDividerSize; + dividerBounds.left = position - mDividerInsets; + dividerBounds.right = dividerBounds.left + mDividerWindowWidth; + bounds1.right = position; + bounds2.left = bounds1.right + mDividerSize; } else { position += mRootBounds.top; - mDividerBounds.top = position - mDividerInsets; - mDividerBounds.bottom = mDividerBounds.top + mDividerWindowWidth; - mBounds1.bottom = position; - mBounds2.top = mBounds1.bottom + mDividerSize; + dividerBounds.top = position - mDividerInsets; + dividerBounds.bottom = dividerBounds.top + mDividerWindowWidth; + bounds1.bottom = position; + bounds2.top = bounds1.bottom + mDividerSize; + } + DockedDividerUtils.sanitizeStackBounds(bounds1, true /** topLeft */); + DockedDividerUtils.sanitizeStackBounds(bounds2, false /** topLeft */); + if (setEffectBounds) { + mSurfaceEffectPolicy.applyDividerPosition(position, isLandscape); } - DockedDividerUtils.sanitizeStackBounds(mBounds1, true /** topLeft */); - DockedDividerUtils.sanitizeStackBounds(mBounds2, false /** topLeft */); - mSurfaceEffectPolicy.applyDividerPosition(position, isLandscape); } /** Inflates {@link DividerView} on the root surface. */ @@ -458,7 +470,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange } ValueAnimator animator = ValueAnimator .ofInt(from, to) - .setDuration(250); + .setDuration(FLING_ANIMATION_DURATION); animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); animator.addUpdateListener( animation -> updateDivideBounds((int) animation.getAnimatedValue())); @@ -480,6 +492,86 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange animator.start(); } + /** Swich both surface position with animation. */ + public void splitSwitching(SurfaceControl.Transaction t, SurfaceControl leash1, + SurfaceControl leash2, Runnable finishCallback) { + final boolean isLandscape = isLandscape(); + final Rect insets = getDisplayInsets(mContext); + insets.set(isLandscape ? insets.left : 0, isLandscape ? 0 : insets.top, + isLandscape ? insets.right : 0, isLandscape ? 0 : insets.bottom); + + final int dividerPos = mDividerSnapAlgorithm.calculateNonDismissingSnapTarget( + isLandscape ? mBounds2.width() : mBounds2.height()).position; + final Rect distBounds1 = new Rect(); + final Rect distBounds2 = new Rect(); + final Rect distDividerBounds = new Rect(); + // Compute dist bounds. + updateBounds(dividerPos, distBounds2, distBounds1, distDividerBounds, + false /* setEffectBounds */); + // Offset to real position under root container. + 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 */); + ValueAnimator animator2 = moveSurface(t, leash2, getRefBounds2(), distBounds2, + true /* alignStart */); + ValueAnimator animator3 = moveSurface(t, getDividerLeash(), getRefDividerBounds(), + distDividerBounds, true /* alignStart */); + + AnimatorSet set = new AnimatorSet(); + set.playTogether(animator1, animator2, animator3); + set.setDuration(FLING_ANIMATION_DURATION); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mDividePosition = dividerPos; + updateBounds(mDividePosition); + finishCallback.run(); + } + }); + set.start(); + } + + private ValueAnimator moveSurface(SurfaceControl.Transaction t, SurfaceControl leash, + Rect start, Rect end, boolean alignStart) { + Rect tempStart = new Rect(start); + Rect tempEnd = new Rect(end); + final float diffX = tempEnd.left - tempStart.left; + final float diffY = tempEnd.top - tempStart.top; + final float diffWidth = tempEnd.width() - tempStart.width(); + final float diffHeight = tempEnd.height() - tempStart.height(); + ValueAnimator animator = ValueAnimator.ofFloat(0, 1); + animator.addUpdateListener(animation -> { + if (leash == null) return; + + final float scale = (float) animation.getAnimatedValue(); + final float distX = tempStart.left + scale * diffX; + 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) { + t.setPosition(leash, distX, distY); + t.setWindowCrop(leash, width, height); + } else { + final int offsetX = width - start.width(); + final int offsetY = height - start.height(); + t.setPosition(leash, distX + offsetX, distY + offsetY); + mTempRect.set(0, 0, width, height); + mTempRect.offsetTo(-offsetX, -offsetY); + t.setCrop(leash, mTempRect); + } + t.apply(); + }); + return animator; + } + private static Rect getDisplayInsets(Context context) { return context.getSystemService(WindowManager.class) .getMaximumWindowMetrics() 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 a68970591adc..6cfb700fc16a 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 @@ -611,6 +611,21 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } + void setSideStagePositionAnimated(@SplitPosition int sideStagePosition) { + if (mSideStagePosition == sideStagePosition) return; + SurfaceControl.Transaction t = mTransactionPool.acquire(); + final StageTaskListener topLeftStage = + mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage; + final StageTaskListener bottomRightStage = + mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage; + mSplitLayout.splitSwitching(t, topLeftStage.mRootLeash, bottomRightStage.mRootLeash, + () -> { + setSideStagePosition(SplitLayout.reversePosition(mSideStagePosition), + null /* wct */); + mTransactionPool.release(t); + }); + } + void setSideStagePosition(@SplitPosition int sideStagePosition, @Nullable WindowContainerTransaction wct) { setSideStagePosition(sideStagePosition, true /* updateBounds */, wct); @@ -1209,7 +1224,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, @Override public void onDoubleTappedDivider() { - setSideStagePosition(SplitLayout.reversePosition(mSideStagePosition), null /* wct */); + setSideStagePositionAnimated(SplitLayout.reversePosition(mSideStagePosition)); mLogger.logSwap(getMainStagePosition(), mMainStage.getTopChildTaskUid(), getSideStagePosition(), mSideStage.getTopChildTaskUid(), mSplitLayout.isLandscape()); |