Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +41 −5 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ import android.graphics.Rect; import android.os.RemoteException; import android.os.SystemClock; import android.util.Log; import android.view.Choreographer; import android.view.Display; import android.view.Surface; import android.view.SurfaceControl; Loading Loading @@ -179,8 +180,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, // This is necessary in case there was a resize animation ongoing when exit PIP // started, in which case the first resize will be skipped to let the exit // operation handle the final resize out of PIP mode. See b/185306679. finishResizeDelayedIfNeeded(() -> { finishResize(tx, destinationBounds, direction, animationType); sendOnPipTransitionFinished(direction); }); } } Loading @@ -196,6 +199,39 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } }; /** * Finishes resizing the PiP, delaying the operation if it has to be synced with the PiP menu. * * This is done to avoid a race condition between the last transaction applied in * onPipAnimationUpdate and the finishResize in onPipAnimationEnd. The transaction in * onPipAnimationUpdate is applied directly from WmShell, while onPipAnimationEnd creates a * WindowContainerTransaction in finishResize, which is to be applied by WmCore later. Normally, * the WCT should be the last transaction to finish the animation. However, it may happen that * it gets applied *before* the transaction created by the last onPipAnimationUpdate. This * happens only when the PiP surface transaction has to be synced with the PiP menu due to the * necessity for a delay when syncing the PiP surface animation with the PiP menu surface * animation and redrawing the PiP menu contents. As a result, the PiP surface gets scaled after * the new bounds are applied by WmCore, which makes the PiP surface have unexpected bounds. * * To avoid this, we delay the finishResize operation until * the next frame. This aligns the last onAnimationUpdate transaction with the WCT application. */ private void finishResizeDelayedIfNeeded(Runnable finishResizeRunnable) { if (!shouldSyncPipTransactionWithMenu()) { finishResizeRunnable.run(); return; } // Delay the finishResize to the next frame Choreographer.getInstance().postCallback(Choreographer.CALLBACK_COMMIT, () -> { mMainExecutor.execute(finishResizeRunnable); }, null); } private boolean shouldSyncPipTransactionWithMenu() { return mPipMenuController.isMenuVisible(); } @VisibleForTesting final PipTransitionController.PipTransitionCallback mPipTransitionCallback = new PipTransitionController.PipTransitionCallback() { Loading @@ -221,7 +257,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, @Override public boolean handlePipTransaction(SurfaceControl leash, SurfaceControl.Transaction tx, Rect destinationBounds) { if (mPipMenuController.isMenuVisible()) { if (shouldSyncPipTransactionWithMenu()) { mPipMenuController.movePipMenu(leash, tx, destinationBounds); return true; } Loading Loading @@ -1223,7 +1259,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mSurfaceTransactionHelper .crop(tx, mLeash, toBounds) .round(tx, mLeash, mPipTransitionState.isInPip()); if (mPipMenuController.isMenuVisible()) { if (shouldSyncPipTransactionWithMenu()) { mPipMenuController.resizePipMenu(mLeash, tx, toBounds); } else { tx.apply(); Loading Loading @@ -1265,7 +1301,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mSurfaceTransactionHelper .scale(tx, mLeash, startBounds, toBounds, degrees) .round(tx, mLeash, startBounds, toBounds); if (mPipMenuController.isMenuVisible()) { if (shouldSyncPipTransactionWithMenu()) { mPipMenuController.movePipMenu(mLeash, tx, toBounds); } else { tx.apply(); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +41 −5 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ import android.graphics.Rect; import android.os.RemoteException; import android.os.SystemClock; import android.util.Log; import android.view.Choreographer; import android.view.Display; import android.view.Surface; import android.view.SurfaceControl; Loading Loading @@ -179,8 +180,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, // This is necessary in case there was a resize animation ongoing when exit PIP // started, in which case the first resize will be skipped to let the exit // operation handle the final resize out of PIP mode. See b/185306679. finishResizeDelayedIfNeeded(() -> { finishResize(tx, destinationBounds, direction, animationType); sendOnPipTransitionFinished(direction); }); } } Loading @@ -196,6 +199,39 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } }; /** * Finishes resizing the PiP, delaying the operation if it has to be synced with the PiP menu. * * This is done to avoid a race condition between the last transaction applied in * onPipAnimationUpdate and the finishResize in onPipAnimationEnd. The transaction in * onPipAnimationUpdate is applied directly from WmShell, while onPipAnimationEnd creates a * WindowContainerTransaction in finishResize, which is to be applied by WmCore later. Normally, * the WCT should be the last transaction to finish the animation. However, it may happen that * it gets applied *before* the transaction created by the last onPipAnimationUpdate. This * happens only when the PiP surface transaction has to be synced with the PiP menu due to the * necessity for a delay when syncing the PiP surface animation with the PiP menu surface * animation and redrawing the PiP menu contents. As a result, the PiP surface gets scaled after * the new bounds are applied by WmCore, which makes the PiP surface have unexpected bounds. * * To avoid this, we delay the finishResize operation until * the next frame. This aligns the last onAnimationUpdate transaction with the WCT application. */ private void finishResizeDelayedIfNeeded(Runnable finishResizeRunnable) { if (!shouldSyncPipTransactionWithMenu()) { finishResizeRunnable.run(); return; } // Delay the finishResize to the next frame Choreographer.getInstance().postCallback(Choreographer.CALLBACK_COMMIT, () -> { mMainExecutor.execute(finishResizeRunnable); }, null); } private boolean shouldSyncPipTransactionWithMenu() { return mPipMenuController.isMenuVisible(); } @VisibleForTesting final PipTransitionController.PipTransitionCallback mPipTransitionCallback = new PipTransitionController.PipTransitionCallback() { Loading @@ -221,7 +257,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, @Override public boolean handlePipTransaction(SurfaceControl leash, SurfaceControl.Transaction tx, Rect destinationBounds) { if (mPipMenuController.isMenuVisible()) { if (shouldSyncPipTransactionWithMenu()) { mPipMenuController.movePipMenu(leash, tx, destinationBounds); return true; } Loading Loading @@ -1223,7 +1259,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mSurfaceTransactionHelper .crop(tx, mLeash, toBounds) .round(tx, mLeash, mPipTransitionState.isInPip()); if (mPipMenuController.isMenuVisible()) { if (shouldSyncPipTransactionWithMenu()) { mPipMenuController.resizePipMenu(mLeash, tx, toBounds); } else { tx.apply(); Loading Loading @@ -1265,7 +1301,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mSurfaceTransactionHelper .scale(tx, mLeash, startBounds, toBounds, degrees) .round(tx, mLeash, startBounds, toBounds); if (mPipMenuController.isMenuVisible()) { if (shouldSyncPipTransactionWithMenu()) { mPipMenuController.movePipMenu(mLeash, tx, toBounds); } else { tx.apply(); Loading