Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e5e9121d authored by Ikram Gabiyev's avatar Ikram Gabiyev
Browse files

[PiP2] Implement expand in fixed rotation

Implement exit-via-expand with fixed rotation
in PiP2.

Also modified WindowToken#getOrCreateFixedRotationLeash()
to not have a fixed rotation leash created when dealing
with a PiP activity (we check for win-mode at transition start,
since we reparent and set windowing mode right away in PiP2).
This should make sure that Shell receives the activity leash,
and that we have no fixed rotation transforms applied on it
during the expand animation.

Bug: 376302431
Flag: com.android.wm.shell.enable_pip2
Test: enter single-activity PiP, then expand
Change-Id: Id6d592876fdd6581ed5a111f0e64d10222296016
parent 70a45498
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import android.view.Choreographer;
import android.view.SurfaceControl;

import com.android.wm.shell.R;
import com.android.wm.shell.transition.Transitions;

/**
 * Abstracts the common operations on {@link SurfaceControl.Transaction} for PiP transition.
@@ -180,8 +179,7 @@ public class PipSurfaceTransactionHelper {
        // destination are different.
        final float scale = srcW <= srcH ? (float) destW / srcW : (float) destH / srcH;
        final Rect crop = mTmpDestinationRect;
        crop.set(0, 0, Transitions.SHELL_TRANSITIONS_ROTATION ? destH
                : destW, Transitions.SHELL_TRANSITIONS_ROTATION ? destW : destH);
        crop.set(0, 0, destW, destH);
        // Inverse scale for crop to fit in screen coordinates.
        crop.scale(1 / scale);
        crop.offset(insets.left, insets.top);
@@ -200,8 +198,8 @@ public class PipSurfaceTransactionHelper {
            }
        }
        mTmpTransform.setScale(scale, scale);
        mTmpTransform.postRotate(degrees);
        mTmpTransform.postTranslate(positionX, positionY);
        mTmpTransform.postRotate(degrees);
        tx.setMatrix(leash, mTmpTransform, mTmpFloat9).setCrop(leash, crop);
        return this;
    }
+31 −15
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.wm.shell.pip2.animation;

import static android.view.Surface.ROTATION_90;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.RectEvaluator;
@@ -73,6 +75,7 @@ public class PipExpandAnimator extends ValueAnimator {
                mAnimationStartCallback.run();
            }
            if (mStartTransaction != null) {
                onExpandAnimationUpdate(mStartTransaction, 0f);
                mStartTransaction.apply();
            }
        }
@@ -81,13 +84,7 @@ public class PipExpandAnimator extends ValueAnimator {
        public void onAnimationEnd(Animator animation) {
            super.onAnimationEnd(animation);
            if (mFinishTransaction != null) {
                // finishTransaction might override some state (eg. corner radii) so we want to
                // manually set the state to the end of the animation
                mPipSurfaceTransactionHelper.scaleAndCrop(mFinishTransaction, mLeash,
                                mSourceRectHint, mBaseBounds, mAnimatedRect, getInsets(1f),
                                false /* isInPipDirection */, 1f)
                        .round(mFinishTransaction, mLeash, false /* applyCornerRadius */)
                        .shadow(mFinishTransaction, mLeash, false /* applyCornerRadius */);
                onExpandAnimationUpdate(mFinishTransaction, 1f);
            }
            if (mAnimationEndCallback != null) {
                mAnimationEndCallback.run();
@@ -102,14 +99,7 @@ public class PipExpandAnimator extends ValueAnimator {
                    final SurfaceControl.Transaction tx =
                            mSurfaceControlTransactionFactory.getTransaction();
                    final float fraction = getAnimatedFraction();

                    // TODO (b/350801661): implement fixed rotation
                    Rect insets = getInsets(fraction);
                    mPipSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mSourceRectHint,
                                    mBaseBounds, mAnimatedRect,
                                    insets, false /* isInPipDirection */, fraction)
                            .round(tx, mLeash, false /* applyCornerRadius */)
                            .shadow(tx, mLeash, false /* applyCornerRadius */);
                    onExpandAnimationUpdate(tx, fraction);
                    tx.apply();
                }
            };
@@ -167,6 +157,32 @@ public class PipExpandAnimator extends ValueAnimator {
        mAnimationEndCallback = runnable;
    }

    private void onExpandAnimationUpdate(SurfaceControl.Transaction tx, float fraction) {
        Rect insets = getInsets(fraction);
        if (mRotation == Surface.ROTATION_0) {
            mPipSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mSourceRectHint, mBaseBounds,
                    mAnimatedRect, insets, false /* isInPipDirection */, fraction);
        } else {
            // Fixed rotation case.
            Rect start = mStartBounds;
            Rect end = mEndBounds;
            float degrees, x, y;
            x = fraction * (end.left - start.left) + start.left;
            y = fraction * (end.top - start.top) + start.top;

            if (mRotation == ROTATION_90) {
                degrees = 90 * fraction;
            } else {
                degrees = -90 * fraction;
            }
            mPipSurfaceTransactionHelper.rotateAndScaleWithCrop(tx, mLeash, mBaseBounds,
                    mAnimatedRect, insets, degrees, x, y,
                    true /* isExpanding */, mRotation == ROTATION_90);
        }
        mPipSurfaceTransactionHelper.round(tx, mLeash, false /* applyCornerRadius */)
                .shadow(tx, mLeash, false /* applyShadowRadius */);
    }

    private Rect getInsets(float fraction) {
        final Rect startInsets = mSourceRectHintInsets;
        final Rect endInsets = mZeroInsets;
+5 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.view.SurfaceControl;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.Preconditions;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.ShellExecutor;
@@ -36,6 +37,7 @@ import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.pip2.animation.PipResizeAnimator;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.annotations.ShellMainThread;

import java.util.ArrayList;
@@ -121,6 +123,9 @@ public class PipTaskListener implements ShellTaskOrganizer.TaskListener,
        if (mPictureInPictureParams.equals(params)) {
            return;
        }
        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                "onTaskInfoChanged: %s, state=%s oldParams=%s newParams=%s",
                taskInfo.topActivity, mPipTransitionState, mPictureInPictureParams, params);
        setPictureInPictureParams(params);
        float newAspectRatio = mPictureInPictureParams.getAspectRatioFloat();
        if (PipUtils.aspectRatioChanged(newAspectRatio, mPipBoundsState.getAspectRatio())) {
+69 −26
Original line number Diff line number Diff line
@@ -325,9 +325,7 @@ public class PipTransition extends PipTransitionController implements
            return false;
        }

        SurfaceControl pipLeash = pipChange.getLeash();
        Preconditions.checkNotNull(pipLeash, "Leash is null for swipe-up transition.");

        final SurfaceControl pipLeash = getLeash(pipChange);
        final Rect destinationBounds = pipChange.getEndAbsBounds();
        final SurfaceControl swipePipToHomeOverlay = mPipTransitionState.getSwipePipToHomeOverlay();
        if (swipePipToHomeOverlay != null) {
@@ -349,7 +347,7 @@ public class PipTransition extends PipTransitionController implements
                : startRotation - endRotation;
        if (delta != ROTATION_0) {
            mPipTransitionState.setInFixedRotation(true);
            handleBoundsTypeFixedRotation(pipChange, pipActivityChange, endRotation);
            handleBoundsEnterFixedRotation(pipChange, pipActivityChange, endRotation);
        }

        Rect sourceRectHint = null;
@@ -420,15 +418,15 @@ public class PipTransition extends PipTransitionController implements
        }

        final TransitionInfo.Change fixedRotationChange = findFixedRotationChange(info);
        int startRotation = pipChange.getStartRotation();
        int endRotation = fixedRotationChange != null
        final int startRotation = pipChange.getStartRotation();
        final int endRotation = fixedRotationChange != null
                ? fixedRotationChange.getEndFixedRotation() : ROTATION_UNDEFINED;
        final int delta = endRotation == ROTATION_UNDEFINED ? ROTATION_0
                : startRotation - endRotation;

        if (delta != ROTATION_0) {
            mPipTransitionState.setInFixedRotation(true);
            handleBoundsTypeFixedRotation(pipChange, pipActivityChange,
            handleBoundsEnterFixedRotation(pipChange, pipActivityChange,
                    fixedRotationChange.getEndFixedRotation());
        }

@@ -465,7 +463,7 @@ public class PipTransition extends PipTransitionController implements
        animator.start();
    }

    private void handleBoundsTypeFixedRotation(TransitionInfo.Change pipTaskChange,
    private void handleBoundsEnterFixedRotation(TransitionInfo.Change pipTaskChange,
            TransitionInfo.Change pipActivityChange, int endRotation) {
        final Rect endBounds = pipTaskChange.getEndAbsBounds();
        final Rect endActivityBounds = pipActivityChange.getEndAbsBounds();
@@ -498,6 +496,26 @@ public class PipTransition extends PipTransitionController implements
                endBounds.top + activityEndOffset.y);
    }

    private void handleExpandFixedRotation(TransitionInfo.Change pipTaskChange, int endRotation) {
        final Rect endBounds = pipTaskChange.getEndAbsBounds();
        final int width = endBounds.width();
        final int height = endBounds.height();
        final int left = endBounds.left;
        final int top = endBounds.top;
        int newTop, newLeft;

        if (endRotation == Surface.ROTATION_90) {
            newLeft = top;
            newTop = -(left + width);
        } else {
            newLeft = -(height + top);
            newTop = left;
        }
        // Modify the endBounds, rotating and placing them potentially off-screen, so that
        // as we translate and rotate around the origin, we place them right into the target.
        endBounds.set(newLeft, newTop, newLeft + height, newTop + width);
    }


    private boolean startAlphaTypeEnterAnimation(@NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction startTransaction,
@@ -550,33 +568,51 @@ public class PipTransition extends PipTransitionController implements
            }
        }

        // for multi activity, we need to manually set the leash layer
        if (pipChange.getTaskInfo() == null) {
            TransitionInfo.Change parent = getChangeByToken(info, pipChange.getParent());
            if (parent != null) {
                startTransaction.setLayer(parent.getLeash(), Integer.MAX_VALUE - 1);
            }
        // The parent change if we were in a multi-activity PiP; null if single activity PiP.
        final TransitionInfo.Change parentBeforePip = pipChange.getTaskInfo() == null
                ? getChangeByToken(info, pipChange.getParent()) : null;
        if (parentBeforePip != null) {
            // For multi activity, we need to manually set the leash layer
            startTransaction.setLayer(parentBeforePip.getLeash(), Integer.MAX_VALUE - 1);
        }

        Rect startBounds = pipChange.getStartAbsBounds();
        Rect endBounds = pipChange.getEndAbsBounds();
        SurfaceControl pipLeash = pipChange.getLeash();
        Preconditions.checkNotNull(pipLeash, "Leash is null for exit transition.");
        final Rect startBounds = pipChange.getStartAbsBounds();
        final Rect endBounds = pipChange.getEndAbsBounds();
        final SurfaceControl pipLeash = getLeash(pipChange);

        Rect sourceRectHint = null;
        if (pipChange.getTaskInfo() != null
                && pipChange.getTaskInfo().pictureInPictureParams != null) {
        PictureInPictureParams params = null;
        if (pipChange.getTaskInfo() != null) {
            // single activity
            sourceRectHint = pipChange.getTaskInfo().pictureInPictureParams.getSourceRectHint();
        } else if (mPipTaskListener.getPictureInPictureParams().hasSourceBoundsHint()) {
            params = pipChange.getTaskInfo().pictureInPictureParams;
        } else if (parentBeforePip != null && parentBeforePip.getTaskInfo() != null) {
            // multi activity
            sourceRectHint = mPipTaskListener.getPictureInPictureParams().getSourceRectHint();
            params = parentBeforePip.getTaskInfo().pictureInPictureParams;
        }
        final Rect sourceRectHint = PipBoundsAlgorithm.getValidSourceHintRect(params, endBounds,
                startBounds);

        final TransitionInfo.Change fixedRotationChange = findFixedRotationChange(info);
        final int startRotation = pipChange.getStartRotation();
        final int endRotation = fixedRotationChange != null
                ? fixedRotationChange.getEndFixedRotation() : ROTATION_UNDEFINED;
        final int delta = endRotation == ROTATION_UNDEFINED ? ROTATION_0
                : endRotation - startRotation;

        if (delta != ROTATION_0) {
            handleExpandFixedRotation(pipChange, endRotation);
        }

        PipExpandAnimator animator = new PipExpandAnimator(mContext, pipLeash,
                startTransaction, finishTransaction, endBounds, startBounds, endBounds,
                sourceRectHint, Surface.ROTATION_0);
        animator.setAnimationEndCallback(this::finishTransition);
                sourceRectHint, delta);
        animator.setAnimationEndCallback(() -> {
            if (parentBeforePip != null) {
                // TODO b/377362511: Animate local leash instead to also handle letterbox case.
                // For multi-activity, set the crop to be null
                finishTransaction.setCrop(pipLeash, null);
            }
            finishTransition();
        });
        animator.start();
        return true;
    }
@@ -723,6 +759,13 @@ public class PipTransition extends PipTransitionController implements
        }
    }

    @NonNull
    private SurfaceControl getLeash(TransitionInfo.Change change) {
        SurfaceControl leash = change.getLeash();
        Preconditions.checkNotNull(leash, "Leash is null for change=" + change);
        return leash;
    }

    //
    // Miscellaneous callbacks and listeners
    //
+6 −0
Original line number Diff line number Diff line
@@ -614,6 +614,12 @@ class WindowToken extends WindowContainer<WindowState> {
        final int rotation = getRelativeDisplayRotation();
        if (rotation == Surface.ROTATION_0) return mFixedRotationTransformLeash;
        if (mFixedRotationTransformLeash != null) return mFixedRotationTransformLeash;
        if (ActivityTaskManagerService.isPip2ExperimentEnabled() && asActivityRecord() != null
                && mTransitionController.getWindowingModeAtStart(
                asActivityRecord()) == WINDOWING_MODE_PINNED) {
            // PiP handles fixed rotation animation in Shell, so do not create the rotation leash.
            return null;
        }

        final SurfaceControl leash = makeSurface().setContainerLayer()
                .setParent(getParentSurfaceControl())