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

Commit b4a15542 authored by Ikram Gabiyev's avatar Ikram Gabiyev Committed by Android (Google) Code Review
Browse files

Merge "Offset src-rect by display cutouts if needed" into main

parents 7a8b6e61 6e1e3a56
Loading
Loading
Loading
Loading
+119 −55
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_PIP;
@@ -230,6 +231,11 @@ public class PipTransition extends PipTransitionController implements
            // If there is no PiP change, exit this transition handler and potentially try others.
            if (pipChange == null) return false;

            // Other targets might have default transforms applied that are not relevant when
            // playing PiP transitions, so reset those transforms if needed.
            prepareOtherTargetTransforms(info, startTransaction, finishTransaction);

            // Update the PipTransitionState while supplying the PiP leash and token to be cached.
            Bundle extra = new Bundle();
            extra.putParcelable(PIP_TASK_TOKEN, pipChange.getContainer());
            extra.putParcelable(PIP_TASK_LEASH, pipChange.getLeash());
@@ -341,17 +347,21 @@ public class PipTransition extends PipTransitionController implements
                            (destinationBounds.height() - overlaySize) / 2f);
        }

        final int startRotation = pipChange.getStartRotation();
        final int endRotation = mPipDisplayLayoutState.getRotation();
        final int delta = endRotation == ROTATION_UNDEFINED ? ROTATION_0
                : startRotation - endRotation;
        final int delta = getFixedRotationDelta(info, pipChange);
        if (delta != ROTATION_0) {
            mPipTransitionState.setInFixedRotation(true);
            handleBoundsEnterFixedRotation(pipChange, pipActivityChange, endRotation);
            // Update transition target changes in place to prepare for fixed rotation.
            handleBoundsEnterFixedRotation(info, pipChange, pipActivityChange);
        }

        // Update the src-rect-hint in params in place, to set up initial animator transform.
        Rect sourceRectHint = getAdjustedSourceRectHint(info, pipChange, pipActivityChange);
        pipChange.getTaskInfo().pictureInPictureParams.getSourceRectHint().set(sourceRectHint);

        // Config-at-end transitions need to have their activities transformed before starting
        // the animation; this makes the buffer seem like it's been updated to final size.
        prepareConfigAtEndActivity(startTransaction, finishTransaction, pipChange,
                pipActivityChange);

        startTransaction.merge(finishTransaction);
        PipEnterAnimator animator = new PipEnterAnimator(mContext, pipLeash,
                startTransaction, finishTransaction, destinationBounds, delta);
@@ -387,55 +397,36 @@ public class PipTransition extends PipTransitionController implements
            return false;
        }

        final SurfaceControl pipLeash = getLeash(pipChange);
        final Rect startBounds = pipChange.getStartAbsBounds();
        final Rect endBounds = pipChange.getEndAbsBounds();

        final PictureInPictureParams params = pipChange.getTaskInfo().pictureInPictureParams;
        final float aspectRatio = mPipBoundsAlgorithm.getAspectRatioOrDefault(params);
        final Rect sourceRectHint = PipBoundsAlgorithm.getValidSourceHintRect(params, startBounds,
                endBounds);
        final Rect adjustedSourceRectHint = sourceRectHint != null ? new Rect(sourceRectHint)
                : PipUtils.getEnterPipWithOverlaySrcRectHint(startBounds, aspectRatio);

        final SurfaceControl pipLeash = mPipTransitionState.getPinnedTaskLeash();

        // For opening type transitions, if there is a change of mode TO_FRONT/OPEN,
        // make sure that change has alpha of 1f, since it's init state might be set to alpha=0f
        // by the Transitions framework to simplify Task opening transitions.
        if (TransitionUtil.isOpeningType(info.getType())) {
            for (TransitionInfo.Change change : info.getChanges()) {
                if (change.getLeash() == null) continue;
                if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) {
                    startTransaction.setAlpha(change.getLeash(), 1f);
                }
            }
        }

        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
                : startRotation - endRotation;
        final Rect adjustedSourceRectHint = getAdjustedSourceRectHint(info, pipChange,
                pipActivityChange);

        final int delta = getFixedRotationDelta(info, pipChange);
        if (delta != ROTATION_0) {
            mPipTransitionState.setInFixedRotation(true);
            handleBoundsEnterFixedRotation(pipChange, pipActivityChange,
                    fixedRotationChange.getEndFixedRotation());
            // Update transition target changes in place to prepare for fixed rotation.
            handleBoundsEnterFixedRotation(info, pipChange, pipActivityChange);
        }

        PipEnterAnimator animator = new PipEnterAnimator(mContext, pipLeash,
                startTransaction, finishTransaction, endBounds, delta);
        if (sourceRectHint == null) {
            // update the src-rect-hint in params in place, to set up initial animator transform.
            params.getSourceRectHint().set(adjustedSourceRectHint);
        if (PipBoundsAlgorithm.getValidSourceHintRect(params, startBounds, endBounds) == null) {
            // If app provided src-rect-hint is invalid, use app icon overlay.
            animator.setAppIconContentOverlay(
                    mContext, startBounds, endBounds, pipChange.getTaskInfo().topActivityInfo,
                    mPipBoundsState.getLauncherState().getAppIconSizePx());
        }

        // Update the src-rect-hint in params in place, to set up initial animator transform.
        params.getSourceRectHint().set(adjustedSourceRectHint);

        // Config-at-end transitions need to have their activities transformed before starting
        // the animation; this makes the buffer seem like it's been updated to final size.
        prepareConfigAtEndActivity(startTransaction, finishTransaction, pipChange,
                pipActivityChange);

        animator.setAnimationStartCallback(() -> animator.setEnterStartState(pipChange));
        animator.setAnimationEndCallback(() -> {
            if (animator.getContentOverlayLeash() != null) {
@@ -457,11 +448,22 @@ public class PipTransition extends PipTransitionController implements
        animator.start();
    }

    private void handleBoundsEnterFixedRotation(TransitionInfo.Change pipTaskChange,
            TransitionInfo.Change pipActivityChange, int endRotation) {
        final Rect endBounds = pipTaskChange.getEndAbsBounds();
        final Rect endActivityBounds = pipActivityChange.getEndAbsBounds();
        int startRotation = pipTaskChange.getStartRotation();
    private void handleBoundsEnterFixedRotation(TransitionInfo info,
            TransitionInfo.Change outPipTaskChange,
            TransitionInfo.Change outPipActivityChange) {
        final TransitionInfo.Change fixedRotationChange = findFixedRotationChange(info);
        final Rect endBounds = outPipTaskChange.getEndAbsBounds();
        final Rect endActivityBounds = outPipActivityChange.getEndAbsBounds();
        int startRotation = outPipTaskChange.getStartRotation();
        int endRotation = fixedRotationChange != null
                ? fixedRotationChange.getEndFixedRotation() : mPipDisplayLayoutState.getRotation();

        if (startRotation == endRotation) {
            return;
        }

        // This is used by display change listeners to respond properly to fixed rotation.
        mPipTransitionState.setInFixedRotation(true);

        // Cache the task to activity offset to potentially restore later.
        Point activityEndOffset = new Point(endActivityBounds.left - endBounds.left,
@@ -490,15 +492,15 @@ public class PipTransition extends PipTransitionController implements
                endBounds.top + activityEndOffset.y);
    }

    private void handleExpandFixedRotation(TransitionInfo.Change pipTaskChange, int endRotation) {
        final Rect endBounds = pipTaskChange.getEndAbsBounds();
    private void handleExpandFixedRotation(TransitionInfo.Change outPipTaskChange, int delta) {
        final Rect endBounds = outPipTaskChange.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) {
        if (delta == Surface.ROTATION_90) {
            newLeft = top;
            newTop = -(left + width);
        } else {
@@ -585,15 +587,11 @@ public class PipTransition extends PipTransitionController implements
        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;

        // We define delta = startRotation - endRotation, so we need to flip the sign.
        final int delta = -getFixedRotationDelta(info, pipChange);
        if (delta != ROTATION_0) {
            handleExpandFixedRotation(pipChange, endRotation);
            // Update PiP target change in place to prepare for fixed rotation;
            handleExpandFixedRotation(pipChange, delta);
        }

        PipExpandAnimator animator = new PipExpandAnimator(mContext, pipLeash,
@@ -661,6 +659,72 @@ public class PipTransition extends PipTransitionController implements
        return null;
    }

    @NonNull
    private Rect getAdjustedSourceRectHint(@NonNull TransitionInfo info,
            @NonNull TransitionInfo.Change pipTaskChange,
            @NonNull TransitionInfo.Change pipActivityChange) {
        final Rect startBounds = pipTaskChange.getStartAbsBounds();
        final Rect endBounds = pipTaskChange.getEndAbsBounds();
        final PictureInPictureParams params = pipTaskChange.getTaskInfo().pictureInPictureParams;

        // Get the source-rect-hint provided by the app and check its validity; null if invalid.
        final Rect sourceRectHint = PipBoundsAlgorithm.getValidSourceHintRect(params, startBounds,
                endBounds);

        final Rect adjustedSourceRectHint = new Rect();
        if (sourceRectHint != null) {
            adjustedSourceRectHint.set(sourceRectHint);
            // If multi-activity PiP, use the parent task before PiP to retrieve display cutouts;
            // then, offset the valid app provided source rect hint by the cutout insets.
            // For single-activity PiP, just use the pinned task to get the cutouts instead.
            TransitionInfo.Change parentBeforePip = pipActivityChange.getLastParent() != null
                    ? getChangeByToken(info, pipActivityChange.getLastParent()) : null;
            Rect cutoutInsets = parentBeforePip != null
                    ? parentBeforePip.getTaskInfo().displayCutoutInsets
                    : pipTaskChange.getTaskInfo().displayCutoutInsets;
            if (cutoutInsets != null
                    && getFixedRotationDelta(info, pipTaskChange) == ROTATION_90) {
                adjustedSourceRectHint.offset(cutoutInsets.left, cutoutInsets.top);
            }
        } else {
            // For non-valid app provided src-rect-hint, calculate one to crop into during
            // app icon overlay animation.
            float aspectRatio = mPipBoundsAlgorithm.getAspectRatioOrDefault(params);
            adjustedSourceRectHint.set(
                    PipUtils.getEnterPipWithOverlaySrcRectHint(startBounds, aspectRatio));
        }
        return adjustedSourceRectHint;
    }

    @Surface.Rotation
    private int getFixedRotationDelta(@NonNull TransitionInfo info,
            @NonNull TransitionInfo.Change pipChange) {
        TransitionInfo.Change fixedRotationChange = findFixedRotationChange(info);
        int startRotation = pipChange.getStartRotation();
        int endRotation = fixedRotationChange != null
                ? fixedRotationChange.getEndFixedRotation() : mPipDisplayLayoutState.getRotation();
        int delta = endRotation == ROTATION_UNDEFINED ? ROTATION_0
                : startRotation - endRotation;
        return delta;
    }

    private void prepareOtherTargetTransforms(TransitionInfo info,
            SurfaceControl.Transaction startTransaction,
            SurfaceControl.Transaction finishTransaction) {
        // For opening type transitions, if there is a change of mode TO_FRONT/OPEN,
        // make sure that change has alpha of 1f, since it's init state might be set to alpha=0f
        // by the Transitions framework to simplify Task opening transitions.
        if (TransitionUtil.isOpeningType(info.getType())) {
            for (TransitionInfo.Change change : info.getChanges()) {
                if (change.getLeash() == null) continue;
                if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) {
                    startTransaction.setAlpha(change.getLeash(), 1f);
                }
            }
        }

    }

    private WindowContainerTransaction getEnterPipTransaction(@NonNull IBinder transition,
            @NonNull TransitionRequestInfo request) {
        // cache the original task token to check for multi-activity case later