From 72b04b7d4dff2af4028e4ea527d2af9fe49e2963 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 24 Jun 2020 19:48:19 -0700 Subject: [PATCH] Updating rotation transaction behaviour - Ensure we use the final animation bounds to calculate the bounds in the new orientation if there is an animation running - If there is an transition animation running during rotation, we need to cancel the animation and not schedule any WCT updates separate from the transaction passed to the display change listener. For this transaction, we specify the bounds change + a surface transaction for the new bounds in the next orientation. Bug: 159397143 Test: atest PinnedStackTests Test: Enter pip in portrait, hold the phone in landscape physically and launch apps + go home repeatedly Change-Id: Ib473654bd0e55492b2bc803faea6825db440bf13 --- .../systemui/pip/PipTaskOrganizer.java | 83 ++++++++++++++----- .../systemui/pip/phone/PipManager.java | 22 +++-- 2 files changed, 78 insertions(+), 27 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index 330b20edf985f..a7dd53e48a817 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -224,6 +224,16 @@ public class PipTaskOrganizer extends TaskOrganizer implements return new Rect(mLastReportedBounds); } + public Rect getCurrentOrAnimatingBounds() { + PipAnimationController.PipTransitionAnimator animator = + mPipAnimationController.getCurrentAnimator(); + if (animator != null && animator.isRunning()) { + System.out.println("RUNNING ANIM: anim=" + animator.getDestinationBounds() + " last=" + getLastReportedBounds()); + return new Rect(animator.getDestinationBounds()); + } + return getLastReportedBounds(); + } + public boolean isInPip() { return mInPip; } @@ -406,7 +416,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements private void sendOnPipTransitionStarted( @PipAnimationController.TransitionDirection int direction) { - mMainHandler.post(() -> { + runOnMainHandler(() -> { for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) { final PipTransitionCallback callback = mPipTransitionCallbacks.get(i); callback.onPipTransitionStarted(mTaskInfo.baseActivity, direction); @@ -416,7 +426,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements private void sendOnPipTransitionFinished( @PipAnimationController.TransitionDirection int direction) { - mMainHandler.post(() -> { + runOnMainHandler(() -> { for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) { final PipTransitionCallback callback = mPipTransitionCallbacks.get(i); callback.onPipTransitionFinished(mTaskInfo.baseActivity, direction); @@ -426,7 +436,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements private void sendOnPipTransitionCancelled( @PipAnimationController.TransitionDirection int direction) { - mMainHandler.post(() -> { + runOnMainHandler(() -> { for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) { final PipTransitionCallback callback = mPipTransitionCallbacks.get(i); callback.onPipTransitionCanceled(mTaskInfo.baseActivity, direction); @@ -434,6 +444,14 @@ public class PipTaskOrganizer extends TaskOrganizer implements }); } + private void runOnMainHandler(Runnable r) { + if (Looper.getMainLooper() == Looper.myLooper()) { + r.run(); + } else { + mMainHandler.post(r); + } + } + /** * Note that dismissing PiP is now originated from SystemUI, see {@link #exitPip(int)}. * Meanwhile this callback is invoked whenever the task is removed. For instance: @@ -505,15 +523,29 @@ public class PipTaskOrganizer extends TaskOrganizer implements */ @SuppressWarnings("unchecked") public void onMovementBoundsChanged(Rect destinationBoundsOut, boolean fromRotation, - boolean fromImeAdjustment, boolean fromShelfAdjustment) { + boolean fromImeAdjustment, boolean fromShelfAdjustment, + WindowContainerTransaction wct) { final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController.getCurrentAnimator(); if (animator == null || !animator.isRunning() || animator.getTransitionDirection() != TRANSITION_DIRECTION_TO_PIP) { if (mInPip && fromRotation) { - // this could happen if rotation finishes before the animation + // If we are rotating while there is a current animation, immediately cancel the + // animation (remove the listeners so we don't trigger the normal finish resize + // call that should only happen on the update thread) + int direction = animator.getTransitionDirection(); + animator.removeAllUpdateListeners(); + animator.removeAllListeners(); + animator.cancel(); + // Do notify the listeners that this was canceled + sendOnPipTransitionCancelled(direction); mLastReportedBounds.set(destinationBoundsOut); - scheduleFinishResizePip(mLastReportedBounds); + + // Create a reset surface transaction for the new bounds and update the window + // container transaction + final SurfaceControl.Transaction tx = createFinishResizeSurfaceTransaction( + destinationBoundsOut); + prepareFinishResizeTransaction(destinationBoundsOut, direction, tx, wct); } else { // There could be an animation on-going. If there is one on-going, last-reported // bounds isn't yet updated. We'll use the animator's bounds instead. @@ -622,7 +654,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements * {@link #scheduleResizePip}. */ public void scheduleFinishResizePip(Rect destinationBounds) { - scheduleFinishResizePip(destinationBounds, null); + scheduleFinishResizePip(destinationBounds, null /* updateBoundsCallback */); } /** @@ -630,30 +662,36 @@ public class PipTaskOrganizer extends TaskOrganizer implements */ public void scheduleFinishResizePip(Rect destinationBounds, Consumer updateBoundsCallback) { - final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); - mSurfaceTransactionHelper - .crop(tx, mLeash, destinationBounds) - .resetScale(tx, mLeash, destinationBounds) - .round(tx, mLeash, mInPip); - scheduleFinishResizePip(tx, destinationBounds, TRANSITION_DIRECTION_NONE, - updateBoundsCallback); + scheduleFinishResizePip(destinationBounds, TRANSITION_DIRECTION_NONE, updateBoundsCallback); } - private void scheduleFinishResizePip(SurfaceControl.Transaction tx, - Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, + private void scheduleFinishResizePip(Rect destinationBounds, + @PipAnimationController.TransitionDirection int direction, Consumer updateBoundsCallback) { if (!mInPip) { // can be initiated in other component, ignore if we are no longer in PIP return; } + SomeArgs args = SomeArgs.obtain(); args.arg1 = updateBoundsCallback; - args.arg2 = tx; + args.arg2 = createFinishResizeSurfaceTransaction( + destinationBounds); args.arg3 = destinationBounds; args.argi1 = direction; mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_FINISH_RESIZE, args)); } + private SurfaceControl.Transaction createFinishResizeSurfaceTransaction( + Rect destinationBounds) { + final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction(); + mSurfaceTransactionHelper + .crop(tx, mLeash, destinationBounds) + .resetScale(tx, mLeash, destinationBounds) + .round(tx, mLeash, mInPip); + return tx; + } + /** * Offset the PiP window by a given offset on Y-axis, triggered also from screen rotation. */ @@ -741,7 +779,15 @@ public class PipTaskOrganizer extends TaskOrganizer implements return; } - final WindowContainerTransaction wct = new WindowContainerTransaction(); + WindowContainerTransaction wct = new WindowContainerTransaction(); + prepareFinishResizeTransaction(destinationBounds, direction, tx, wct); + applyFinishBoundsResize(wct, direction); + } + + private void prepareFinishResizeTransaction(Rect destinationBounds, + @PipAnimationController.TransitionDirection int direction, + SurfaceControl.Transaction tx, + WindowContainerTransaction wct) { final Rect taskBounds; if (isInPipDirection(direction)) { // If we are animating from fullscreen using a bounds animation, then reset the @@ -762,7 +808,6 @@ public class PipTaskOrganizer extends TaskOrganizer implements wct.setBounds(mToken, taskBounds); wct.setBoundsChangeTransaction(mToken, tx); - applyFinishBoundsResize(wct, direction); } /** diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index 7a18ec3618609..1fbe58d28d394 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -36,6 +36,7 @@ import android.util.Log; import android.util.Pair; import android.view.DisplayInfo; import android.view.IPinnedStackController; +import android.view.SurfaceControl; import android.window.WindowContainerTransaction; import com.android.systemui.Dependency; @@ -94,9 +95,12 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio */ private final DisplayChangeController.OnDisplayChangingListener mRotationController = ( int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> { + // If there is an animation running (ie. from a shelf offset), then ensure that we calculate + // the bounds for the next orientation using the destination bounds of the animation + // TODO: Techincally this should account for movement animation bounds as well + Rect currentBounds = mPipTaskOrganizer.getCurrentOrAnimatingBounds(); final boolean changed = mPipBoundsHandler.onDisplayRotationChanged(mTmpNormalBounds, - mPipTaskOrganizer.getLastReportedBounds(), mTmpInsetBounds, displayId, fromRotation, - toRotation, t); + currentBounds, mTmpInsetBounds, displayId, fromRotation, toRotation, t); if (changed) { // If the pip was in the offset zone earlier, adjust the new bounds to the bottom of the // movement bounds @@ -116,7 +120,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio } updateMovementBounds(mTmpNormalBounds, true /* fromRotation */, - false /* fromImeAdjustment */, false /* fromShelfAdjustment */); + false /* fromImeAdjustment */, false /* fromShelfAdjustment */, t); } }; @@ -194,7 +198,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio @Override public void onMovementBoundsChanged(boolean fromImeAdjustment) { mHandler.post(() -> updateMovementBounds(null /* toBounds */, - false /* fromRotation */, fromImeAdjustment, false /* fromShelfAdjustment */)); + false /* fromRotation */, fromImeAdjustment, false /* fromShelfAdjustment */, + null /* windowContainerTransaction */)); } @Override @@ -327,7 +332,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mTouchHandler.onShelfVisibilityChanged(visible, shelfHeight); updateMovementBounds(mPipTaskOrganizer.getLastReportedBounds(), false /* fromRotation */, false /* fromImeAdjustment */, - true /* fromShelfAdjustment */); + true /* fromShelfAdjustment */, null /* windowContainerTransaction */); } }); } @@ -387,15 +392,16 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio } private void updateMovementBounds(@Nullable Rect toBounds, boolean fromRotation, - boolean fromImeAdjustment, boolean fromShelfAdjustment) { + boolean fromImeAdjustment, boolean fromShelfAdjustment, + WindowContainerTransaction wct) { // Populate inset / normal bounds and DisplayInfo from mPipBoundsHandler before // passing to mTouchHandler/mPipTaskOrganizer final Rect outBounds = new Rect(toBounds); mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds, outBounds, mTmpDisplayInfo); // mTouchHandler would rely on the bounds populated from mPipTaskOrganizer - mPipTaskOrganizer.onMovementBoundsChanged(outBounds, fromRotation, - fromImeAdjustment, fromShelfAdjustment); + mPipTaskOrganizer.onMovementBoundsChanged(outBounds, fromRotation, fromImeAdjustment, + fromShelfAdjustment, wct); mTouchHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds, outBounds, fromImeAdjustment, fromShelfAdjustment, mTmpDisplayInfo.rotation);