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
This commit is contained in:
Galia Peycheva
2022-11-10 17:50:24 +01:00
parent 236f36de43
commit 5d08f2e5ca

View File

@@ -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);
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);
updateMenuBounds(pipDestBounds);
// 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 maybeCreateSyncApplier() {
if (mPipMenuView == null || mPipMenuView.getViewRootImpl() == null) {
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);
}
}