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

Commit 7d6b8e74 authored by Ben Lin's avatar Ben Lin
Browse files

Implement PIP Leash resizing.

This CL does a couple of things:
- Break apart resizePinnedStack into animateResizeStack and
resizeStackIntermediate, in which the latter is expected to only do
maniuplation on the leash itself but don't send any
WindowContainerTransaction until #finishResize is called.
- Break apart the coupling where the duration signifies whether we only
do manipulation on the leash, or send over a WCT. Now we can choose to
either resize leash only, or animate correctly an entire resize with
animation = 0.
- Have PipResizeGestureHandler call on #finishResize and
resizePipStackIntermediate during MOVE and UP events, respectively

Bug: 147361175
Test: Manually. Resize PIP.
Change-Id: Id3953904a7d626880855eab043abfb8d8a8d9b11
parent 39c9570d
Loading
Loading
Loading
Loading
+91 −46
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ package com.android.systemui.pip;

import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
import static com.android.systemui.pip.PipAnimationController.DURATION_NONE;
import static com.android.systemui.pip.PipAnimationController.DURATION_DEFAULT_MS;

import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -87,19 +87,7 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
                }
            });
            final Rect destinationBounds = animator.getDestinationBounds();
            mLastReportedBounds.set(destinationBounds);
            try {
                final WindowContainerTransaction wct = new WindowContainerTransaction();
                if (animator.shouldScheduleFinishPip()) {
                    wct.scheduleFinishEnterPip(wc, destinationBounds);
                } else {
                    wct.setBounds(wc, destinationBounds);
                }
                wct.setBoundsChangeTransaction(wc, tx);
                mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */);
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to apply container transaction", e);
            }
            finishResizeInternal(destinationBounds, wc, tx, animator.shouldScheduleFinishPip());
        }

        @Override
@@ -124,15 +112,6 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
        mPipAnimationController = new PipAnimationController(context);
    }

    /**
     * Resize the PiP window, animate if the given duration is not {@link #DURATION_NONE}
     */
    public void resizePinnedStack(Rect destinationBounds, int durationMs) {
        Objects.requireNonNull(mTaskInfo, "Requires valid IWindowContainer");
        resizePinnedStackInternal(mTaskInfo.token, false /* scheduleFinishPip */,
                mLastReportedBounds, destinationBounds, durationMs);
    }

    /**
     * Offset the PiP window, animate if the given duration is not {@link #DURATION_NONE}
     */
@@ -143,7 +122,7 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
        }
        final Rect destinationBounds = new Rect(originalBounds);
        destinationBounds.offset(xOffset, yOffset);
        resizePinnedStackInternal(mTaskInfo.token, false /* scheduleFinishPip*/,
        animateResizePipInternal(mTaskInfo.token, false /* scheduleFinishPip*/,
                originalBounds, destinationBounds, durationMs);
    }

@@ -208,15 +187,14 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
        mTaskInfo = info;
        if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
            final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
            resizePinnedStackInternal(mTaskInfo.token, true /* scheduleFinishPip */,
                    currentBounds, destinationBounds,
                    PipAnimationController.DURATION_DEFAULT_MS);
            animateResizePipInternal(mTaskInfo.token, true /* scheduleFinishPip */,
                    currentBounds, destinationBounds, DURATION_DEFAULT_MS);
        } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
            mMainHandler.post(() -> mPipAnimationController
                    .getAnimator(mTaskInfo.token, true /* scheduleFinishPip */,
                            destinationBounds, 0f, 1f)
                    .setPipAnimationCallback(mPipAnimationCallback)
                    .setDuration(PipAnimationController.DURATION_DEFAULT_MS)
                    .setDuration(DURATION_DEFAULT_MS)
                    .start());
            mOneShotAnimationType = ANIM_TYPE_BOUNDS;
        } else {
@@ -231,9 +209,8 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
            Log.wtf(TAG, "Unrecognized token: " + token);
            return;
        }
        resizePinnedStackInternal(token, false /* scheduleFinishPip */,
                mLastReportedBounds, mDisplayBounds,
                PipAnimationController.DURATION_DEFAULT_MS);
        animateResizePipInternal(token, false /* scheduleFinishPip */,
                mLastReportedBounds, mDisplayBounds, DURATION_DEFAULT_MS);
    }

    @Override
@@ -245,11 +222,22 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
        final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
                getAspectRatioOrDefault(info.pictureInPictureParams), null /* bounds */);
        Objects.requireNonNull(destinationBounds, "Missing destination bounds");
        resizePinnedStack(destinationBounds, PipAnimationController.DURATION_DEFAULT_MS);
        animateResizePip(destinationBounds, DURATION_DEFAULT_MS);
    }

    private void resizePinnedStackInternal(IWindowContainer wc, boolean scheduleFinishPip,
            Rect currentBounds, Rect destinationBounds, int animationDurationMs) {

    /**
     * Directly perform manipulation/resize on the leash. This will not perform any
     * {@link WindowContainerTransaction} until {@link #finishResize} is called.
     */
    public void resizePip(Rect destinationBounds) {
        Objects.requireNonNull(mTaskInfo, "Requires valid IWindowContainer");
        resizePipInternal(mTaskInfo.token, destinationBounds);
    }

    private void resizePipInternal(IWindowContainer wc,
            Rect destinationBounds) {
        Objects.requireNonNull(mTaskInfo, "Requires valid IWindowContainer");
        try {
            // Could happen when dismissPip
            if (wc == null || wc.getLeash() == null) {
@@ -257,20 +245,76 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
                return;
            }
            final SurfaceControl leash = wc.getLeash();
            if (animationDurationMs == DURATION_NONE) {
                // Directly resize if no animation duration is set. When fling, wait for final
                // callback to issue the proper WindowContainerTransaction with destination bounds.
            new SurfaceControl.Transaction()
                    .setPosition(leash, destinationBounds.left, destinationBounds.top)
                    .setWindowCrop(leash, destinationBounds.width(), destinationBounds.height())
                    .apply();
        } catch (RemoteException e) {
            Log.w(TAG, "Abort animation, invalid window container", e);
        } catch (Exception e) {
            Log.e(TAG, "Should not reach here, terrible thing happened", e);
        }
    }

    /**
     * Finish a intermediate resize operation. This is expected to be called after
     * {@link #resizePip}.
     */
    public void finishResize(Rect destinationBounds) {
        try {
            final IWindowContainer wc = mTaskInfo.token;
            SurfaceControl.Transaction tx = new SurfaceControl.Transaction()
                    .setPosition(wc.getLeash(), destinationBounds.left,
                            destinationBounds.top)
                    .setWindowCrop(wc.getLeash(), destinationBounds.width(),
                            destinationBounds.height());
            finishResizeInternal(destinationBounds, wc, tx, false);
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to obtain leash");
        }
    }

    private void finishResizeInternal(Rect destinationBounds, IWindowContainer wc,
            SurfaceControl.Transaction tx, boolean shouldScheduleFinishPip) {
        mLastReportedBounds.set(destinationBounds);
        try {
            final WindowContainerTransaction wct = new WindowContainerTransaction();
            if (shouldScheduleFinishPip) {
                wct.scheduleFinishEnterPip(wc, destinationBounds);
            } else {
                wct.setBounds(wc, destinationBounds);
            }
            wct.setBoundsChangeTransaction(mTaskInfo.token, tx);
            mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */);
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to apply container transaction", e);
        }
    }

    /**
     * Animates resizing of the pinned stack given the duration.
     */
    public void animateResizePip(Rect destinationBounds, int durationMs) {
        Objects.requireNonNull(mTaskInfo, "Requires valid IWindowContainer");
        animateResizePipInternal(mTaskInfo.token, false, mLastReportedBounds,
                destinationBounds, durationMs);
    }

    private void animateResizePipInternal(IWindowContainer wc, boolean scheduleFinishPip,
            Rect currentBounds, Rect destinationBounds, int durationMs) {
        try {
            // Could happen when dismissPip
            if (wc == null || wc.getLeash() == null) {
                Log.w(TAG, "Abort animation, invalid leash");
                return;
            }
            final SurfaceControl leash = wc.getLeash();

            mMainHandler.post(() -> mPipAnimationController
                    .getAnimator(wc, scheduleFinishPip, currentBounds, destinationBounds)
                    .setPipAnimationCallback(mPipAnimationCallback)
                        .setDuration(animationDurationMs)
                    .setDuration(durationMs)
                    .start());
            }
        } catch (RemoteException e) {
            Log.w(TAG, "Abort animation, invalid window container", e);
        } catch (Exception e) {
@@ -278,6 +322,7 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub {
        }
    }


    private float getAspectRatioOrDefault(@Nullable PictureInPictureParams params) {
        return params == null
                ? mPipBoundsHandler.getDefaultAspectRatio()
+2 −3
Original line number Diff line number Diff line
@@ -38,7 +38,6 @@ import androidx.dynamicanimation.animation.SpringForce;

import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.internal.os.SomeArgs;
import com.android.systemui.pip.PipAnimationController;
import com.android.systemui.pip.PipSnapAlgorithm;
import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -546,7 +545,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
            case MSG_RESIZE_IMMEDIATE: {
                SomeArgs args = (SomeArgs) msg.obj;
                Rect toBounds = (Rect) args.arg1;
                mPipTaskOrganizer.resizePinnedStack(toBounds, PipAnimationController.DURATION_NONE);
                mPipTaskOrganizer.resizePip(toBounds);
                mBounds.set(toBounds);
                return true;
            }
@@ -564,7 +563,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call
                        return true;
                    }

                    mPipTaskOrganizer.resizePinnedStack(toBounds, duration);
                    mPipTaskOrganizer.animateResizePip(toBounds, duration);
                    mBounds.set(toBounds);
                } catch (RemoteException e) {
                    Log.e(TAG, "Could not animate resize pinned stack to bounds: " + toBounds, e);
+7 −3
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import android.view.MotionEvent;
import com.android.internal.policy.TaskResizingAlgorithm;
import com.android.systemui.R;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.util.DeviceConfigProxy;

import java.util.concurrent.Executor;
@@ -75,12 +76,13 @@ public class PipResizeGestureHandler {

    private InputMonitor mInputMonitor;
    private InputEventReceiver mInputEventReceiver;
    private PipTaskOrganizer mPipTaskOrganizer;

    private int mCtrlType;

    public PipResizeGestureHandler(Context context, PipBoundsHandler pipBoundsHandler,
            PipTouchHandler pipTouchHandler, PipMotionHelper motionHelper,
            DeviceConfigProxy deviceConfig) {
            DeviceConfigProxy deviceConfig, PipTaskOrganizer pipTaskOrganizer) {
        final Resources res = context.getResources();
        context.getDisplay().getMetrics(mDisplayMetrics);
        mDisplayId = context.getDisplayId();
@@ -88,6 +90,7 @@ public class PipResizeGestureHandler {
        mPipBoundsHandler = pipBoundsHandler;
        mPipTouchHandler = pipTouchHandler;
        mMotionHelper = motionHelper;
        mPipTaskOrganizer = pipTaskOrganizer;

        context.getDisplay().getRealSize(mMaxSize);
        mDelta = res.getDimensionPixelSize(R.dimen.pip_resize_edge_size);
@@ -205,12 +208,13 @@ public class PipResizeGestureHandler {
                            mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x,
                            mMinSize.y, mMaxSize, true, true));
                    mPipBoundsHandler.transformBoundsToAspectRatio(mLastResizeBounds);
                    //TODO: Actually do resize here.
                    mPipTaskOrganizer.resizePip(mLastResizeBounds);

                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    mPipTaskOrganizer.finishResize(mLastResizeBounds);
                    mLastResizeBounds.setEmpty();
                    //TODO: Finish resize operation here.
                    mCtrlType = CTRL_NONE;
                    mAllowGesture = false;
                    break;
+1 −1
Original line number Diff line number Diff line
@@ -191,7 +191,7 @@ public class PipTouchHandler {
                mMenuController, mSnapAlgorithm, mFlingAnimationUtils, floatingContentCoordinator);
        mPipResizeGestureHandler =
                new PipResizeGestureHandler(context, pipBoundsHandler, this, mMotionHelper,
                        deviceConfig);
                        deviceConfig, pipTaskOrganizer);
        mTouchState = new PipTouchState(ViewConfiguration.get(context), mHandler,
                () -> mMenuController.showMenu(MENU_STATE_FULL, mMotionHelper.getBounds(),
                        mMovementBounds, true /* allowMenuTimeout */, willResizeMenu()));
+2 −2
Original line number Diff line number Diff line
@@ -433,8 +433,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
                mCurrentPipBounds = mPipBounds;
                break;
        }
        mPipTaskOrganizer.resizePinnedStack(
                mCurrentPipBounds, PipAnimationController.DURATION_DEFAULT_MS);
        mPipTaskOrganizer.animateResizePip(mCurrentPipBounds,
                PipAnimationController.DURATION_DEFAULT_MS);
    }

    /**