diff options
Diffstat (limited to 'libs')
4 files changed, 141 insertions, 26 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java index 4aeecbec7dfb..4d5dc6da6ee5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java @@ -176,12 +176,12 @@ public class PipAnimationController { public PipTransitionAnimator getAnimator(TaskInfo taskInfo, SurfaceControl leash, Rect baseBounds, Rect startBounds, Rect endBounds, Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction, float startingAngle, - @Surface.Rotation int rotationDelta) { + @Surface.Rotation int rotationDelta, boolean alwaysAnimateTaskBounds) { if (mCurrentAnimator == null) { mCurrentAnimator = setupPipTransitionAnimator( PipTransitionAnimator.ofBounds(taskInfo, leash, startBounds, startBounds, endBounds, sourceHintRect, direction, 0 /* startingAngle */, - rotationDelta)); + rotationDelta, alwaysAnimateTaskBounds)); } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA && mCurrentAnimator.isRunning()) { // If we are still animating the fade into pip, then just move the surface and ensure @@ -197,7 +197,8 @@ public class PipAnimationController { mCurrentAnimator.cancel(); mCurrentAnimator = setupPipTransitionAnimator( PipTransitionAnimator.ofBounds(taskInfo, leash, baseBounds, startBounds, - endBounds, sourceHintRect, direction, startingAngle, rotationDelta)); + endBounds, sourceHintRect, direction, startingAngle, rotationDelta, + alwaysAnimateTaskBounds)); } return mCurrentAnimator; } @@ -585,28 +586,29 @@ public class PipAnimationController { static PipTransitionAnimator<Rect> ofBounds(TaskInfo taskInfo, SurfaceControl leash, Rect baseValue, Rect startValue, Rect endValue, Rect sourceRectHint, @PipAnimationController.TransitionDirection int direction, float startingAngle, - @Surface.Rotation int rotationDelta) { + @Surface.Rotation int rotationDelta, boolean alwaysAnimateTaskBounds) { final boolean isOutPipDirection = isOutPipDirection(direction); final boolean isInPipDirection = isInPipDirection(direction); // Just for simplicity we'll interpolate between the source rect hint insets and empty // insets to calculate the window crop final Rect initialSourceValue; final Rect mainWindowFrame = taskInfo.topActivityMainWindowFrame; - final boolean hasNonMatchFrame = mainWindowFrame != null; + // For the animation to swipe PIP to home or restore a PIP task from home, we don't + // override to the main window frame since we should animate the whole task. + final boolean shouldUseMainWindowFrame = mainWindowFrame != null + && !alwaysAnimateTaskBounds; final boolean changeOrientation = rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270; final Rect baseBounds = new Rect(baseValue); final Rect startBounds = new Rect(startValue); final Rect endBounds = new Rect(endValue); if (isOutPipDirection) { - // TODO(b/356277166): handle rotation change with activity that provides main window - // frame. - if (hasNonMatchFrame && !changeOrientation) { + if (shouldUseMainWindowFrame && !changeOrientation) { endBounds.set(mainWindowFrame); } initialSourceValue = new Rect(endBounds); } else if (isInPipDirection) { - if (hasNonMatchFrame) { + if (shouldUseMainWindowFrame) { baseBounds.set(mainWindowFrame); if (startValue.equals(baseValue)) { // If the start value is at initial state as in PIP animation, also override @@ -635,9 +637,19 @@ public class PipAnimationController { if (changeOrientation) { lastEndRect = new Rect(endBounds); rotatedEndRect = new Rect(endBounds); - // Rotate the end bounds according to the rotation delta because the display will - // be rotated to the same orientation. - rotateBounds(rotatedEndRect, initialSourceValue, rotationDelta); + // TODO(b/375977163): polish the animation to restoring the PIP task back from + // swipe-pip-to-home. Ideally we should send the transitionInfo after reparenting + // the PIP activity back to the original task. + if (shouldUseMainWindowFrame) { + // If we should animate the main window frame, set it to the rotatedRect + // instead. The end bounds reported by transitionInfo is the bounds before + // rotation, while main window frame is calculated after the rotation. + rotatedEndRect.set(mainWindowFrame); + } else { + // Rotate the end bounds according to the rotation delta because the display + // will be rotated to the same orientation. + rotateBounds(rotatedEndRect, initialSourceValue, rotationDelta); + } // Use the rect that has the same orientation as the hint rect. initialContainerRect = isOutPipDirection ? rotatedEndRect : initialSourceValue; } else { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index c4e63dfdade9..abe50b33625b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -1838,9 +1838,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, ? mPipBoundsState.getBounds() : currentBounds; final boolean existingAnimatorRunning = mPipAnimationController.getCurrentAnimator() != null && mPipAnimationController.getCurrentAnimator().isRunning(); + // For resize animation, we always animate the whole PIP task bounds. final PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController .getAnimator(mTaskInfo, mLeash, baseBounds, currentBounds, destinationBounds, - sourceHintRect, direction, startingAngle, rotationDelta); + sourceHintRect, direction, startingAngle, rotationDelta, + true /* alwaysAnimateTaskBounds */); animator.setTransitionDirection(direction) .setPipTransactionHandler(mPipTransactionHandler) .setDuration(durationMs); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index 28b91c6cb812..8c1be5ffa19c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -884,7 +884,8 @@ public class PipTransition extends PipTransitionController { final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController.getAnimator(taskInfo, pipChange.getLeash(), startBounds, startBounds, endBounds, null, TRANSITION_DIRECTION_LEAVE_PIP, - 0 /* startingAngle */, pipRotateDelta); + 0 /* startingAngle */, pipRotateDelta, + false /* alwaysAnimateTaskBounds */); animator.setTransitionDirection(TRANSITION_DIRECTION_LEAVE_PIP) .setPipAnimationCallback(mPipAnimationCallback) .setDuration(mEnterExitAnimationDuration) @@ -899,7 +900,7 @@ public class PipTransition extends PipTransitionController { final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController.getAnimator(taskInfo, leash, baseBounds, startBounds, endBounds, sourceHintRect, TRANSITION_DIRECTION_LEAVE_PIP, - 0 /* startingAngle */, rotationDelta); + 0 /* startingAngle */, rotationDelta, false /* alwaysAnimateTaskBounds */); animator.setTransitionDirection(TRANSITION_DIRECTION_LEAVE_PIP) .setDuration(mEnterExitAnimationDuration); if (startTransaction != null) { @@ -1095,8 +1096,6 @@ public class PipTransition extends PipTransitionController { if (taskInfo.pictureInPictureParams != null && taskInfo.pictureInPictureParams.isAutoEnterEnabled() && mPipTransitionState.getInSwipePipToHomeTransition()) { - // TODO(b/356277166): add support to swipe PIP to home with - // non-match parent activity. handleSwipePipToHomeTransition(startTransaction, finishTransaction, leash, sourceHintRect, destinationBounds, taskInfo); return; @@ -1118,7 +1117,7 @@ public class PipTransition extends PipTransitionController { if (enterAnimationType == ANIM_TYPE_BOUNDS) { animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds, currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP, - 0 /* startingAngle */, rotationDelta); + 0 /* startingAngle */, rotationDelta, false /* alwaysAnimateTaskBounds */); if (sourceHintRect == null) { // We use content overlay when there is no source rect hint to enter PiP use bounds // animation. We also temporarily disallow app icon overlay and use color overlay @@ -1241,10 +1240,14 @@ public class PipTransition extends PipTransitionController { // to avoid flicker. final Rect savedDisplayCutoutInsets = new Rect(pipTaskInfo.displayCutoutInsets); pipTaskInfo.displayCutoutInsets.setEmpty(); + // Always use the task bounds even if the PIP activity doesn't match parent because the app + // and the whole task will move behind. We should animate the whole task bounds in this + // case. final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController.getAnimator(pipTaskInfo, leash, sourceBounds, sourceBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP, - 0 /* startingAngle */, ROTATION_0 /* rotationDelta */) + 0 /* startingAngle */, ROTATION_0 /* rotationDelta */, + true /* alwaysAnimateTaskBounds */) .setPipTransactionHandler(mTransactionConsumer) .setTransitionDirection(TRANSITION_DIRECTION_TO_PIP); // The start state is the end state for swipe-auto-pip. diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java index 72950a8dc139..4dca595b97c5 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java @@ -93,7 +93,8 @@ public class PipAnimationControllerTest extends ShellTestCase { final Rect endValue1 = new Rect(100, 100, 200, 200); final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController .getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue1, null, - TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0); + TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0, + false /* alwaysAnimateTaskBounds */); assertEquals("Expect ANIM_TYPE_BOUNDS animation", animator.getAnimationType(), PipAnimationController.ANIM_TYPE_BOUNDS); @@ -107,14 +108,16 @@ public class PipAnimationControllerTest extends ShellTestCase { final Rect endValue2 = new Rect(200, 200, 300, 300); final PipAnimationController.PipTransitionAnimator oldAnimator = mPipAnimationController .getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue1, null, - TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0); + TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0, + false /* alwaysAnimateTaskBounds */); oldAnimator.setSurfaceControlTransactionFactory( MockSurfaceControlHelper::createMockSurfaceControlTransaction); oldAnimator.start(); final PipAnimationController.PipTransitionAnimator newAnimator = mPipAnimationController .getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue2, null, - TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0); + TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0, + false /* alwaysAnimateTaskBounds */); assertEquals("getAnimator with same type returns same animator", oldAnimator, newAnimator); @@ -145,7 +148,8 @@ public class PipAnimationControllerTest extends ShellTestCase { // Fullscreen to PiP. PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController .getAnimator(mTaskInfo, mLeash, null, startBounds, endBounds, null, - TRANSITION_DIRECTION_LEAVE_PIP, 0, ROTATION_90); + TRANSITION_DIRECTION_LEAVE_PIP, 0, ROTATION_90, + false /* alwaysAnimateTaskBounds */); // Apply fraction 1 to compute the end value. animator.applySurfaceControlTransaction(mLeash, tx, 1); final Rect rotatedEndBounds = new Rect(endBounds); @@ -157,7 +161,8 @@ public class PipAnimationControllerTest extends ShellTestCase { startBounds.set(0, 0, 1000, 500); endBounds.set(200, 100, 400, 500); animator = mPipAnimationController.getAnimator(mTaskInfo, mLeash, startBounds, startBounds, - endBounds, null, TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_270); + endBounds, null, TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_270, + false /* alwaysAnimateTaskBounds */); animator.applySurfaceControlTransaction(mLeash, tx, 1); rotatedEndBounds.set(endBounds); rotateBounds(rotatedEndBounds, startBounds, ROTATION_270); @@ -166,6 +171,37 @@ public class PipAnimationControllerTest extends ShellTestCase { } @Test + public void pipTransitionAnimator_rotatedEndValue_overrideMainWindowFrame() { + final SurfaceControl.Transaction tx = createMockSurfaceControlTransaction(); + final Rect startBounds = new Rect(200, 700, 400, 800); + final Rect endBounds = new Rect(0, 0, 500, 1000); + mTaskInfo.topActivityMainWindowFrame = new Rect(0, 250, 1000, 500); + + // Fullscreen task to PiP. + PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController + .getAnimator(mTaskInfo, mLeash, null, startBounds, endBounds, null, + TRANSITION_DIRECTION_LEAVE_PIP, 0, ROTATION_90, + false /* alwaysAnimateTaskBounds */); + // Apply fraction 1 to compute the end value. + animator.applySurfaceControlTransaction(mLeash, tx, 1); + + assertEquals("Expect use main window frame", mTaskInfo.topActivityMainWindowFrame, + animator.mCurrentValue); + + // PiP to fullscreen. + mTaskInfo.topActivityMainWindowFrame = new Rect(0, 250, 1000, 500); + startBounds.set(0, 0, 1000, 500); + endBounds.set(200, 100, 400, 500); + animator = mPipAnimationController.getAnimator(mTaskInfo, mLeash, startBounds, startBounds, + endBounds, null, TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_270, + false /* alwaysAnimateTaskBounds */); + animator.applySurfaceControlTransaction(mLeash, tx, 1); + + assertEquals("Expect use main window frame", mTaskInfo.topActivityMainWindowFrame, + animator.mCurrentValue); + } + + @Test @SuppressWarnings("unchecked") public void pipTransitionAnimator_updateEndValue() { final Rect baseValue = new Rect(0, 0, 100, 100); @@ -174,7 +210,8 @@ public class PipAnimationControllerTest extends ShellTestCase { final Rect endValue2 = new Rect(200, 200, 300, 300); final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController .getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue1, null, - TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0); + TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0, + false /* alwaysAnimateTaskBounds */); animator.updateEndValue(endValue2); @@ -188,7 +225,8 @@ public class PipAnimationControllerTest extends ShellTestCase { final Rect endValue = new Rect(100, 100, 200, 200); final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController .getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue, null, - TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0); + TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0, + false /* alwaysAnimateTaskBounds */); animator.setSurfaceControlTransactionFactory( MockSurfaceControlHelper::createMockSurfaceControlTransaction); @@ -207,4 +245,64 @@ public class PipAnimationControllerTest extends ShellTestCase { verify(mPipAnimationCallback).onPipAnimationEnd(eq(mTaskInfo), any(SurfaceControl.Transaction.class), eq(animator)); } + + @Test + public void pipTransitionAnimator_overrideMainWindowFrame() { + final Rect baseValue = new Rect(0, 0, 100, 100); + final Rect startValue = new Rect(0, 0, 100, 100); + final Rect endValue = new Rect(100, 100, 200, 200); + mTaskInfo.topActivityMainWindowFrame = new Rect(0, 50, 100, 100); + PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController + .getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue, null, + TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0, + false /* alwaysAnimateTaskBounds */); + + assertEquals("Expect base value is overridden for in-PIP transition", + mTaskInfo.topActivityMainWindowFrame, animator.getBaseValue()); + assertEquals("Expect start value is overridden for in-PIP transition", + mTaskInfo.topActivityMainWindowFrame, animator.getStartValue()); + assertEquals("Expect end value is not overridden for in-PIP transition", + endValue, animator.getEndValue()); + + animator = mPipAnimationController.getAnimator(mTaskInfo, mLeash, baseValue, startValue, + endValue, null, TRANSITION_DIRECTION_LEAVE_PIP, 0, ROTATION_0, + false /* alwaysAnimateTaskBounds */); + + assertEquals("Expect base value is not overridden for leave-PIP transition", + baseValue, animator.getBaseValue()); + assertEquals("Expect start value is not overridden for leave-PIP transition", + startValue, animator.getStartValue()); + assertEquals("Expect end value is overridden for leave-PIP transition", + mTaskInfo.topActivityMainWindowFrame, animator.getEndValue()); + } + + @Test + public void pipTransitionAnimator_animateTaskBounds() { + final Rect baseValue = new Rect(0, 0, 100, 100); + final Rect startValue = new Rect(0, 0, 100, 100); + final Rect endValue = new Rect(100, 100, 200, 200); + mTaskInfo.topActivityMainWindowFrame = new Rect(0, 50, 100, 100); + PipAnimationController.PipTransitionAnimator<?> animator = mPipAnimationController + .getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue, null, + TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0, + true /* alwaysAnimateTaskBounds */); + + assertEquals("Expect base value is not overridden for in-PIP transition", + baseValue, animator.getBaseValue()); + assertEquals("Expect start value is not overridden for in-PIP transition", + startValue, animator.getStartValue()); + assertEquals("Expect end value is not overridden for in-PIP transition", + endValue, animator.getEndValue()); + + animator = mPipAnimationController.getAnimator(mTaskInfo, mLeash, baseValue, startValue, + endValue, null, TRANSITION_DIRECTION_LEAVE_PIP, 0, ROTATION_0, + true /* alwaysAnimateTaskBounds */); + + assertEquals("Expect base value is not overridden for leave-PIP transition", + baseValue, animator.getBaseValue()); + assertEquals("Expect start value is not overridden for leave-PIP transition", + startValue, animator.getStartValue()); + assertEquals("Expect end value is not overridden for leave-PIP transition", + endValue, animator.getEndValue()); + } } |