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

Commit 410f7326 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Make PiP window functional after moving displays." into main

parents 671d5e9b d50fcd72
Loading
Loading
Loading
Loading
+18 −0
Original line number Original line Diff line number Diff line
@@ -460,6 +460,24 @@ public class PipBoundsAlgorithm {
        return adjustedNormalBounds;
        return adjustedNormalBounds;
    }
    }


    /**
     * Snaps PiP bounds to its movement bounds.
     */
    public void snapToMovementBoundsEdge(Rect bounds) {
        // Get the current movement bounds
        final Rect movementBounds = getMovementBounds(bounds);
        final int leftEdge = bounds.left;

        final int fromLeft = Math.abs(leftEdge - movementBounds.left);
        final int fromRight = Math.abs(movementBounds.right - leftEdge);

        // The PIP will be snapped to either the right or left edge, so calculate which one
        // is closest to the current position.
        final int newLeft = fromLeft < fromRight
                ? movementBounds.left : movementBounds.right;

        bounds.offsetTo(newLeft, bounds.top);
    }
    /**
    /**
     * Dumps internal states.
     * Dumps internal states.
     */
     */
+4 −2
Original line number Original line Diff line number Diff line
@@ -226,10 +226,12 @@ public abstract class Pip2Module {
    static PipDisplayTransferHandler providePipDisplayTransferHandler(Context context,
    static PipDisplayTransferHandler providePipDisplayTransferHandler(Context context,
            PipTransitionState pipTransitionState,
            PipTransitionState pipTransitionState,
            PipScheduler pipScheduler, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
            PipScheduler pipScheduler, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
            PipBoundsState pipBoundsState, DisplayController displayController
            PipBoundsState pipBoundsState, DisplayController displayController,
            PipDisplayLayoutState pipDisplayLayoutState, PipBoundsAlgorithm pipBoundsAlgorithm
    ) {
    ) {
        return new PipDisplayTransferHandler(context, pipTransitionState, pipScheduler,
        return new PipDisplayTransferHandler(context, pipTransitionState, pipScheduler,
                rootTaskDisplayAreaOrganizer, pipBoundsState, displayController);
                rootTaskDisplayAreaOrganizer, pipBoundsState, displayController,
                pipDisplayLayoutState, pipBoundsAlgorithm);
    }
    }


    @WMSingleton
    @WMSingleton
+3 −24
Original line number Original line Diff line number Diff line
@@ -537,21 +537,8 @@ public class PipResizeGestureHandler {
        }
        }
    }
    }


    private void snapToMovementBoundsEdge(Rect bounds, Rect movementBounds) {
        final int leftEdge = bounds.left;




        final int fromLeft = Math.abs(leftEdge - movementBounds.left);
        final int fromRight = Math.abs(movementBounds.right - leftEdge);

        // The PIP will be snapped to either the right or left edge, so calculate which one
        // is closest to the current position.
        final int newLeft = fromLeft < fromRight
                ? movementBounds.left : movementBounds.right;

        bounds.offsetTo(newLeft, mLastResizeBounds.top);
    }

    /**
    /**
     * Resizes the pip window and updates user-resized bounds.
     * Resizes the pip window and updates user-resized bounds.
     *
     *
@@ -561,11 +548,8 @@ public class PipResizeGestureHandler {
    void userResizeTo(Rect bounds, float snapFraction) {
    void userResizeTo(Rect bounds, float snapFraction) {
        Rect finalBounds = new Rect(bounds);
        Rect finalBounds = new Rect(bounds);


        // get the current movement bounds
        final Rect movementBounds = mPipBoundsAlgorithm.getMovementBounds(finalBounds);

        // snap the target bounds to the either left or right edge, by choosing the closer one
        // snap the target bounds to the either left or right edge, by choosing the closer one
        snapToMovementBoundsEdge(finalBounds, movementBounds);
        mPipBoundsAlgorithm.snapToMovementBoundsEdge(bounds);


        // apply the requested snap fraction onto the target bounds
        // apply the requested snap fraction onto the target bounds
        mPipBoundsAlgorithm.applySnapFraction(finalBounds, snapFraction);
        mPipBoundsAlgorithm.applySnapFraction(finalBounds, snapFraction);
@@ -597,15 +581,10 @@ public class PipResizeGestureHandler {
                    resizeRectAboutCenter(mLastResizeBounds, mMinSize.x, mMinSize.y);
                    resizeRectAboutCenter(mLastResizeBounds, mMinSize.x, mMinSize.y);
                }
                }


                // get the current movement bounds
                final Rect movementBounds = mPipBoundsAlgorithm
                        .getMovementBounds(mLastResizeBounds);

                // snap mLastResizeBounds to the correct edge based on movement bounds
                // snap mLastResizeBounds to the correct edge based on movement bounds
                snapToMovementBoundsEdge(mLastResizeBounds, movementBounds);
                mPipBoundsAlgorithm.snapToMovementBoundsEdge(mLastResizeBounds);


                final float snapFraction = mPipBoundsAlgorithm.getSnapFraction(
                final float snapFraction = mPipBoundsAlgorithm.getSnapFraction(mLastResizeBounds);
                        mLastResizeBounds, movementBounds);
                mPipBoundsAlgorithm.applySnapFraction(mLastResizeBounds, snapFraction);
                mPipBoundsAlgorithm.applySnapFraction(mLastResizeBounds, snapFraction);


                // disable any touch events beyond resizing too
                // disable any touch events beyond resizing too
+101 −17
Original line number Original line Diff line number Diff line
@@ -15,7 +15,11 @@
 */
 */
package com.android.wm.shell.pip2.phone;
package com.android.wm.shell.pip2.phone;


import static com.android.wm.shell.pip2.phone.PipTransition.ANIMATING_BOUNDS_CHANGE_DURATION;
import static com.android.wm.shell.pip2.phone.PipTransition.PIP_DESTINATION_BOUNDS;

import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.TaskInfo;
import android.content.Context;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.RectF;
@@ -27,12 +31,17 @@ import android.view.SurfaceControl.Transaction;
import androidx.annotation.NonNull;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.VisibleForTesting;


import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.MultiDisplayDragMoveBoundsCalculator;
import com.android.wm.shell.common.MultiDisplayDragMoveBoundsCalculator;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipDisplayLayoutState;
import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip2.animation.PipResizeAnimator;
import com.android.wm.shell.protolog.ShellProtoLogGroup;


/**
/**
 * Handler for moving PiP window to another display when the device is connected to external
 * Handler for moving PiP window to another display when the device is connected to external
@@ -53,14 +62,21 @@ public class PipDisplayTransferHandler implements
    private final DisplayController mDisplayController;
    private final DisplayController mDisplayController;
    private final PipTransitionState mPipTransitionState;
    private final PipTransitionState mPipTransitionState;
    private final PipScheduler mPipScheduler;
    private final PipScheduler mPipScheduler;
    private final Context mContext;
    private final PipDisplayLayoutState mPipDisplayLayoutState;
    private final PipBoundsAlgorithm mPipBoundsAlgorithm;


    @VisibleForTesting boolean mWaitingForDisplayTransfer;
    @VisibleForTesting boolean mWaitingForDisplayTransfer;
    @VisibleForTesting
    @VisibleForTesting
    ArrayMap<Integer, SurfaceControl> mOnDragMirrorPerDisplayId = new ArrayMap<>();
    ArrayMap<Integer, SurfaceControl> mOnDragMirrorPerDisplayId = new ArrayMap<>();
    private int mTargetDisplayId;
    private PipResizeAnimatorSupplier mPipResizeAnimatorSupplier;


    public PipDisplayTransferHandler(Context context, PipTransitionState pipTransitionState,
    public PipDisplayTransferHandler(Context context, PipTransitionState pipTransitionState,
            PipScheduler pipScheduler, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
            PipScheduler pipScheduler, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
            PipBoundsState pipBoundsState, DisplayController displayController) {
            PipBoundsState pipBoundsState, DisplayController displayController,
            PipDisplayLayoutState pipDisplayLayoutState, PipBoundsAlgorithm pipBoundsAlgorithm) {
        mContext = context;
        mPipTransitionState = pipTransitionState;
        mPipTransitionState = pipTransitionState;
        mPipTransitionState.addPipTransitionStateChangedListener(this);
        mPipTransitionState.addPipTransitionStateChangedListener(this);
        mPipScheduler = pipScheduler;
        mPipScheduler = pipScheduler;
@@ -70,12 +86,20 @@ public class PipDisplayTransferHandler implements
        mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context);
        mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context);
        mPipBoundsState = pipBoundsState;
        mPipBoundsState = pipBoundsState;
        mDisplayController = displayController;
        mDisplayController = displayController;
        mPipDisplayLayoutState = pipDisplayLayoutState;
        mPipBoundsAlgorithm = pipBoundsAlgorithm;
        mPipResizeAnimatorSupplier = PipResizeAnimator::new;
    }
    }


    void scheduleMovePipToDisplay(int originDisplayId, int targetDisplayId) {
    void scheduleMovePipToDisplay(int originDisplayId, int targetDisplayId,
            Rect destinationBounds) {
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                "%s scheduleMovePipToDisplay from=%d to=%d", TAG, originDisplayId, targetDisplayId);

        Bundle extra = new Bundle();
        Bundle extra = new Bundle();
        extra.putInt(ORIGIN_DISPLAY_ID_KEY, originDisplayId);
        extra.putInt(ORIGIN_DISPLAY_ID_KEY, originDisplayId);
        extra.putInt(TARGET_DISPLAY_ID_KEY, targetDisplayId);
        extra.putInt(TARGET_DISPLAY_ID_KEY, targetDisplayId);
        extra.putParcelable(PIP_DESTINATION_BOUNDS, destinationBounds);


        mPipTransitionState.setState(PipTransitionState.SCHEDULED_BOUNDS_CHANGE, extra);
        mPipTransitionState.setState(PipTransitionState.SCHEDULED_BOUNDS_CHANGE, extra);
    }
    }
@@ -83,36 +107,77 @@ public class PipDisplayTransferHandler implements
    @Override
    @Override
    public void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState,
    public void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState,
            @PipTransitionState.TransitionState int newState, @Nullable Bundle extra) {
            @PipTransitionState.TransitionState int newState, @Nullable Bundle extra) {
        if (extra == null) return;

        switch (newState) {
        switch (newState) {
            case PipTransitionState.SCHEDULED_BOUNDS_CHANGE:
            case PipTransitionState.SCHEDULED_BOUNDS_CHANGE:
                if (extra == null || !extra.containsKey(ORIGIN_DISPLAY_ID_KEY)
                if (!extra.containsKey(ORIGIN_DISPLAY_ID_KEY) || !extra.containsKey(
                        || !extra.containsKey(TARGET_DISPLAY_ID_KEY)) {
                        TARGET_DISPLAY_ID_KEY)) {
                    break;
                }

                final int originDisplayId = extra.getInt(ORIGIN_DISPLAY_ID_KEY);
                mTargetDisplayId = extra.getInt(TARGET_DISPLAY_ID_KEY);
                if (originDisplayId == mTargetDisplayId) {
                    break;
                    break;
                }
                }
                mWaitingForDisplayTransfer = true;


                mPipScheduler.scheduleMoveToDisplay(extra.getInt(ORIGIN_DISPLAY_ID_KEY),
                mWaitingForDisplayTransfer = true;
                        extra.getInt(TARGET_DISPLAY_ID_KEY));
                mPipScheduler.scheduleMoveToDisplay(mTargetDisplayId,
                        extra.getParcelable(PIP_DESTINATION_BOUNDS, Rect.class));
                break;
                break;
            case PipTransitionState.CHANGING_PIP_BOUNDS:
            case PipTransitionState.CHANGING_PIP_BOUNDS:
                if (extra == null || !mWaitingForDisplayTransfer) {
                if (!mWaitingForDisplayTransfer) {
                    break;
                    break;
                }
                }
                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                        "%s Animating PiP display change to=%d", TAG, mTargetDisplayId);


                SurfaceControl pipLeash = mPipTransitionState.getPinnedTaskLeash();
                TaskInfo taskInfo = mPipTransitionState.getPipTaskInfo();
                final int duration = extra.getInt(ANIMATING_BOUNDS_CHANGE_DURATION,
                        PipTransition.BOUNDS_CHANGE_JUMPCUT_DURATION);
                final Transaction startTx = extra.getParcelable(
                final Transaction startTx = extra.getParcelable(
                        PipTransition.PIP_START_TX, Transaction.class);
                        PipTransition.PIP_START_TX, Transaction.class);
                final Rect destinationBounds = extra.getParcelable(
                final Transaction finishTx = extra.getParcelable(
                        PipTransition.PIP_DESTINATION_BOUNDS, Rect.class);
                        PipTransition.PIP_FINISH_TX, Transaction.class);
                final Rect pipBounds = extra.getParcelable(
                        PIP_DESTINATION_BOUNDS, Rect.class);


                startMoveToDisplayAnimation(startTx, destinationBounds);
                Rect finalBounds = new Rect(pipBounds);
        }
                mPipBoundsAlgorithm.snapToMovementBoundsEdge(finalBounds);
    }


    private void startMoveToDisplayAnimation(Transaction startTx, Rect destinationBounds) {
                mPipSurfaceTransactionHelper.round(startTx, pipLeash, true).shadow(startTx,
        if (startTx == null) return;
                        pipLeash, true /* applyShadowRadius */);
                // Set state to exiting and exited PiP to unregister input consumer on the current
                // display.
                // TODO(b/414864788): Refactor transition states setting during display transfer
                mPipTransitionState.setState(PipTransitionState.EXITING_PIP);
                mPipTransitionState.setState(PipTransitionState.EXITED_PIP);


        startTx.apply();
                mPipDisplayLayoutState.setDisplayId(mTargetDisplayId);
        mPipScheduler.scheduleFinishPipBoundsChange(destinationBounds);
                mPipDisplayLayoutState.setDisplayLayout(mDisplayController.getDisplayLayout(
                        mTargetDisplayId));
                mPipTransitionState.setPinnedTaskLeash(pipLeash);
                mPipTransitionState.setPipTaskInfo(taskInfo);

                final PipResizeAnimator animator = mPipResizeAnimatorSupplier.get(mContext,
                        mPipSurfaceTransactionHelper, pipLeash, startTx, finishTx,
                        pipBounds, pipBounds, finalBounds, duration, 0);

                animator.setAnimationEndCallback(() -> {
                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                            "%s Finished animating PiP display change to=%d", TAG,
                            mTargetDisplayId);
                    mPipScheduler.scheduleFinishPipBoundsChange(finalBounds);
                    // Set state to ENTERED_PIP to register input consumer on the target display
                    mPipTransitionState.setState(PipTransitionState.ENTERED_PIP);
                    mPipBoundsState.setHasUserResizedPip(true);
                    mWaitingForDisplayTransfer = false;
                });
                animator.start();
                break;
        }
    }
    }


    /**
    /**
@@ -188,4 +253,23 @@ public class PipDisplayTransferHandler implements
    void setSurfaceTransactionHelper(PipSurfaceTransactionHelper surfaceTransactionHelper) {
    void setSurfaceTransactionHelper(PipSurfaceTransactionHelper surfaceTransactionHelper) {
        mPipSurfaceTransactionHelper = surfaceTransactionHelper;
        mPipSurfaceTransactionHelper = surfaceTransactionHelper;
    }
    }

    @VisibleForTesting
    interface PipResizeAnimatorSupplier {
        PipResizeAnimator get(@NonNull Context context,
                @NonNull PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
                @NonNull SurfaceControl leash,
                @Nullable SurfaceControl.Transaction startTx,
                @Nullable SurfaceControl.Transaction finishTx,
                @NonNull Rect baseBounds,
                @NonNull Rect startBounds,
                @NonNull Rect endBounds,
                int duration,
                float delta);
    }

    @VisibleForTesting
    void setPipResizeAnimatorSupplier(@NonNull PipResizeAnimatorSupplier supplier) {
        mPipResizeAnimatorSupplier = supplier;
    }
}
}
+6 −1
Original line number Original line Diff line number Diff line
@@ -140,6 +140,8 @@ public class PipInputConsumer {
        final InputChannel inputChannel = new InputChannel();
        final InputChannel inputChannel = new InputChannel();
        try {
        try {
            final int displayId = mPipDisplayLayoutState.getDisplayId();
            final int displayId = mPipDisplayLayoutState.getDisplayId();
            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                    "%s: Creating input consumer on displayID: %d", TAG, displayId);
            mWindowManager.destroyInputConsumer(mToken, displayId);
            mWindowManager.destroyInputConsumer(mToken, displayId);
            mWindowManager.createInputConsumer(mToken, mName, displayId, inputChannel);
            mWindowManager.createInputConsumer(mToken, mName, displayId, inputChannel);
        } catch (RemoteException e) {
        } catch (RemoteException e) {
@@ -163,7 +165,10 @@ public class PipInputConsumer {
            return;
            return;
        }
        }
        try {
        try {
            mWindowManager.destroyInputConsumer(mToken, mPipDisplayLayoutState.getDisplayId());
            final int displayId = mPipDisplayLayoutState.getDisplayId();
            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                    "%s: Destroying input consumer on displayID: %d", TAG, displayId);
            mWindowManager.destroyInputConsumer(mToken, displayId);
        } catch (RemoteException e) {
        } catch (RemoteException e) {
            ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
            ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                    "%s: Failed to destroy input consumer, %s", TAG, e);
                    "%s: Failed to destroy input consumer, %s", TAG, e);
Loading