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

Commit 5d08f2e5 authored by Galia Peycheva's avatar Galia Peycheva
Browse files

Use SurfaceSyncGroup to sync the pip move animation

This includes synchronizing the following:
- the Pip transaction
- mPipMenuView (which is in surface A)
- mPipMenuBackgroundView (which is in surface B)
- resizing surface A (done through SystemWindows)
- resizing surface B (done through SystemWindows)
- changing the position of surface A
- changing the position of surface B

Bug: 226580399
Bug: 264361031
Test: move the pip window around the screen and verify that all the 3
      surafces move together
Change-Id: Ie09f0ae7f02229a2f6f560955f7832d26d8d032a
parent 236f36de
Loading
Loading
Loading
Loading
+51 −104
Original line number Diff line number Diff line
@@ -25,16 +25,14 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
import android.view.View;
import android.view.ViewRootImpl;
import android.view.WindowManagerGlobal;
import android.window.SurfaceSyncGroup;

import androidx.annotation.Nullable;

@@ -71,12 +69,6 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
    // exiting the move menu instead of showing the regular button menu.
    private boolean mCloseAfterExitMoveMenu;

    private SyncRtSurfaceTransactionApplier mApplier;
    private SyncRtSurfaceTransactionApplier mBackgroundApplier;
    RectF mTmpSourceRectF = new RectF();
    RectF mTmpDestinationRectF = new RectF();
    Matrix mMoveTransform = new Matrix();

    public TvPipMenuController(Context context, TvPipBoundsState tvPipBoundsState,
            SystemWindows systemWindows, Handler mainHandler) {
        mContext = context;
@@ -324,44 +316,36 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
     */
    @Override
    public void resizePipMenu(@Nullable SurfaceControl pipLeash,
            @Nullable SurfaceControl.Transaction t,
            Rect destinationBounds) {
            @Nullable SurfaceControl.Transaction pipTx,
            Rect pipBounds) {
        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                "%s: resizePipMenu: %s", TAG, destinationBounds.toShortString());
        if (destinationBounds.isEmpty()) {
                "%s: resizePipMenu: %s", TAG, pipBounds.toShortString());
        if (pipBounds.isEmpty()) {
            return;
        }

        if (!maybeCreateSyncApplier()) {
        if (!isMenuReadyToMove()) {
            return;
        }

        final Rect menuBounds = calculateMenuSurfaceBounds(destinationBounds);

        final SurfaceControl frontSurface = getSurfaceControl(mPipMenuView);
        final SyncRtSurfaceTransactionApplier.SurfaceParams frontParams =
                new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(frontSurface)
                        .withWindowCrop(menuBounds)
                        .build();

        final SurfaceControl backSurface = getSurfaceControl(mPipBackgroundView);
        final SyncRtSurfaceTransactionApplier.SurfaceParams backParams =
                new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(backSurface)
                        .withWindowCrop(menuBounds)
                        .build();

        // TODO(b/226580399): switch to using SurfaceSyncer (see b/200284684) to synchronize the
        // animations of the pip surface with the content of the front and back menu surfaces
        mBackgroundApplier.scheduleApply(backParams);
        if (pipLeash != null && t != null) {
            final SyncRtSurfaceTransactionApplier.SurfaceParams
                    pipParams = new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(pipLeash)
                    .withMergeTransaction(t)
                    .build();
            mApplier.scheduleApply(frontParams, pipParams);
        } else {
            mApplier.scheduleApply(frontParams);
        final Rect menuBounds = calculateMenuSurfaceBounds(pipBounds);
        if (pipTx == null) {
            pipTx = new SurfaceControl.Transaction();
        }
        pipTx.setWindowCrop(frontSurface, menuBounds.width(), menuBounds.height());
        pipTx.setWindowCrop(backSurface, menuBounds.width(), menuBounds.height());

        // Synchronize drawing the content in the front and back surfaces together with the pip
        // transaction and the window crop for the front and back surfaces
        final SurfaceSyncGroup syncGroup = new SurfaceSyncGroup("TvPip");
        syncGroup.add(mPipMenuView.getRootSurfaceControl(), null);
        syncGroup.add(mPipBackgroundView.getRootSurfaceControl(), null);
        updateMenuBounds(pipBounds);
        syncGroup.addTransaction(pipTx);
        syncGroup.markSyncReady();
    }

    private SurfaceControl getSurfaceControl(View v) {
@@ -369,102 +353,66 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
    }

    @Override
    public void movePipMenu(SurfaceControl pipLeash, SurfaceControl.Transaction transaction,
            Rect pipDestBounds) {
    public void movePipMenu(SurfaceControl pipLeash, SurfaceControl.Transaction pipTx,
            Rect pipBounds) {
        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                "%s: movePipMenu: %s", TAG, pipDestBounds.toShortString());
                "%s: movePipMenu: %s", TAG, pipBounds.toShortString());

        if (pipDestBounds.isEmpty()) {
            if (transaction == null) {
        if (pipBounds.isEmpty()) {
            if (pipTx == null) {
                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                        "%s: no transaction given", TAG);
            }
            return;
        }
        if (!maybeCreateSyncApplier()) {
        if (!isMenuReadyToMove()) {
            return;
        }

        final Rect menuDestBounds = calculateMenuSurfaceBounds(pipDestBounds);
        final Rect tmpSourceBounds = new Rect();
        // If there is no pip leash supplied, that means the PiP leash is already finalized
        // resizing and the PiP menu is also resized. We then want to do a scale from the current
        // new menu bounds.
        if (pipLeash != null && transaction != null) {
            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                    "%s: tmpSourceBounds based on mPipMenuView.getBoundsOnScreen()", TAG);
            mPipMenuView.getBoundsOnScreen(tmpSourceBounds);
        } else {
            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                    "%s: tmpSourceBounds based on menu width and height", TAG);
            tmpSourceBounds.set(0, 0, menuDestBounds.width(), menuDestBounds.height());
        }

        mTmpSourceRectF.set(tmpSourceBounds);
        mTmpDestinationRectF.set(menuDestBounds);
        mMoveTransform.setTranslate(mTmpDestinationRectF.left, mTmpDestinationRectF.top);

        final SurfaceControl frontSurface = getSurfaceControl(mPipMenuView);
        final SyncRtSurfaceTransactionApplier.SurfaceParams frontParams =
                new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(frontSurface)
                        .withMatrix(mMoveTransform)
                        .build();

        final SurfaceControl backSurface = getSurfaceControl(mPipBackgroundView);
        final SyncRtSurfaceTransactionApplier.SurfaceParams backParams =
                new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(backSurface)
                        .withMatrix(mMoveTransform)
                        .build();

        // TODO(b/226580399): switch to using SurfaceSyncer (see b/200284684) to synchronize the
        // animations of the pip surface with the content of the front and back menu surfaces
        mBackgroundApplier.scheduleApply(backParams);
        if (pipLeash != null && transaction != null) {
            final SyncRtSurfaceTransactionApplier.SurfaceParams pipParams =
                    new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(pipLeash)
                            .withMergeTransaction(transaction)
                            .build();
            mApplier.scheduleApply(frontParams, pipParams);
        } else {
            mApplier.scheduleApply(frontParams);
        }

        updateMenuBounds(pipDestBounds);
    }

    private boolean maybeCreateSyncApplier() {
        if (mPipMenuView == null || mPipMenuView.getViewRootImpl() == null) {
        final Rect menuDestBounds = calculateMenuSurfaceBounds(pipBounds);
        if (pipTx == null) {
            pipTx = new SurfaceControl.Transaction();
        }
        pipTx.setPosition(frontSurface, menuDestBounds.left, menuDestBounds.top);
        pipTx.setPosition(backSurface, menuDestBounds.left, menuDestBounds.top);

        // Synchronize drawing the content in the front and back surfaces together with the pip
        // transaction and the position change for the front and back surfaces
        final SurfaceSyncGroup syncGroup = new SurfaceSyncGroup("TvPip");
        syncGroup.add(mPipMenuView.getRootSurfaceControl(), null);
        syncGroup.add(mPipBackgroundView.getRootSurfaceControl(), null);
        updateMenuBounds(pipBounds);
        syncGroup.addTransaction(pipTx);
        syncGroup.markSyncReady();
    }

    private boolean isMenuReadyToMove() {
        final boolean ready = mPipMenuView != null && mPipMenuView.getViewRootImpl() != null
                && mPipBackgroundView != null && mPipBackgroundView.getViewRootImpl() != null;
        if (!ready) {
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                    "%s: Not going to move PiP, either menu or its parent is not created.", TAG);
            return false;
        }

        if (mApplier == null) {
            mApplier = new SyncRtSurfaceTransactionApplier(mPipMenuView);
        }
        if (mBackgroundApplier == null) {
            mBackgroundApplier = new SyncRtSurfaceTransactionApplier(mPipBackgroundView);
        }
        return true;
        return ready;
    }

    private void detachPipMenu() {
        if (mPipMenuView != null) {
            mApplier = null;
            mSystemWindows.removeView(mPipMenuView);
            mPipMenuView = null;
        }

        if (mPipBackgroundView != null) {
            mBackgroundApplier = null;
            mSystemWindows.removeView(mPipBackgroundView);
            mPipBackgroundView = null;
        }
    }

    @Override
    public void updateMenuBounds(Rect destinationBounds) {
        final Rect menuBounds = calculateMenuSurfaceBounds(destinationBounds);
    public void updateMenuBounds(Rect pipBounds) {
        final Rect menuBounds = calculateMenuSurfaceBounds(pipBounds);
        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                "%s: updateMenuBounds: %s", TAG, menuBounds.toShortString());
        mSystemWindows.updateViewLayout(mPipBackgroundView,
@@ -473,9 +421,8 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
        mSystemWindows.updateViewLayout(mPipMenuView,
                getPipMenuLayoutParams(mContext, MENU_WINDOW_TITLE, menuBounds.width(),
                        menuBounds.height()));

        if (mPipMenuView != null) {
            mPipMenuView.updateBounds(destinationBounds);
            mPipMenuView.updateBounds(pipBounds);
        }
    }