Settle auto PiP transaction in WindowContainerTransaction

At the end of autoEnterPip transition, followings happen in sequence
- Transition finishes in Launcher side, which operates on the
  animation leash
- RecentsAnimationController.TaskAnimationAdapter#onCleanup has the final
  chance to set the Task leash
- PipTaskOrganizer gets onTaskAppeared callback and commits Task into
  pinned mode

What's been changed here
- Transition in Launcher no longer in charge of settle the final transaction
- RecentsAnimationController.TaskAnimationAdapter#onCleanup sets the
  Task leash to be in sync with the final state in Launcher side
- PipTaskOrganizer commits the final leash transaction together with
  WindowContainerTransaction that enters PiP

Known issue: transition from landscape is not polished

Video: http://rcll/aaaaaabFQoRHlzixHdtY/hT5SXvaCy28P4UtfuoKiDw
Bug: 181342797
Test: see video
Change-Id: Ieabd6991ea5174099714ec22970198bebde1e336
This commit is contained in:
Hongwei Wang
2021-03-09 15:16:33 -08:00
parent 9c907184d5
commit f4dfb7c4a3
6 changed files with 61 additions and 33 deletions

View File

@@ -43,8 +43,11 @@ interface IRecentsAnimationController {
* accordingly. This should be called before `finish`
* @param taskId for which the leash should be updated
* @param destinationBounds bounds of the final PiP window
* @param windowCrop bounds to crop as part of final transform.
* @param float9 An array of 9 floats to be used as matrix transform.
*/
void setFinishTaskBounds(int taskId, in Rect destinationBounds);
void setFinishTaskBounds(int taskId, in Rect destinationBounds, in Rect windowCrop,
in float[] float9);
/**
* Notifies to the system that the animation into Recents should end, and all leashes associated

View File

@@ -41,6 +41,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.PictureInPictureParams;
@@ -423,12 +424,16 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
if (mInSwipePipToHomeTransition) {
final Rect destinationBounds = mPipBoundsState.getBounds();
final SurfaceControl.Transaction tx =
mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper.resetScale(tx, mLeash, destinationBounds);
mSurfaceTransactionHelper.crop(tx, mLeash, destinationBounds);
// animation is finished in the Launcher and here we directly apply the final touch.
applyEnterPipSyncTransaction(destinationBounds, () -> {
// ensure menu's settled in its final bounds first
finishResizeForMenu(destinationBounds);
sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
});
}, tx);
mInSwipePipToHomeTransition = false;
return;
}
@@ -490,16 +495,20 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
// mState is set right after the animation is kicked off to block any resize
// requests such as offsetPip that may have been called prior to the transition.
mState = State.ENTERING_PIP;
});
}, null /* boundsChangeTransaction */);
}
private void applyEnterPipSyncTransaction(Rect destinationBounds, Runnable runnable) {
private void applyEnterPipSyncTransaction(Rect destinationBounds, Runnable runnable,
@Nullable SurfaceControl.Transaction boundsChangeTransaction) {
// PiP menu is attached late in the process here to avoid any artifacts on the leash
// caused by addShellRoot when in gesture navigation mode.
mPipMenuController.attach(mLeash);
final WindowContainerTransaction wct = new WindowContainerTransaction();
wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
wct.setBounds(mToken, destinationBounds);
if (boundsChangeTransaction != null) {
wct.setBoundsChangeTransaction(mToken, boundsChangeTransaction);
}
wct.scheduleFinishEnterPip(mToken, destinationBounds);
mSyncTransactionQueue.queue(wct);
if (runnable != null) {

View File

@@ -20,7 +20,6 @@ import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.view.Choreographer;
import android.view.Surface;
import android.view.SurfaceControl;
/**
@@ -91,24 +90,6 @@ public class PipSurfaceTransactionHelper {
.setPosition(leash, positionX, positionY);
}
public void reset(SurfaceControl.Transaction tx, SurfaceControl leash, Rect destinationBounds,
@Surface.Rotation int rotation) {
resetScale(tx, leash, destinationBounds);
if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
final int degree = (rotation == Surface.ROTATION_90) ? -90 : 90;
mTmpTransform.setRotate(degree, 0, 0);
tx.setMatrix(leash, mTmpTransform, mTmpFloat9);
}
resetCornerRadius(tx, leash);
crop(tx, leash, destinationBounds);
}
public void resetScale(SurfaceControl.Transaction tx, SurfaceControl leash,
Rect destinationBounds) {
tx.setMatrix(leash, Matrix.IDENTITY_MATRIX, mTmpFloat9)
.setPosition(leash, destinationBounds.left, destinationBounds.top);
}
public void resetCornerRadius(SurfaceControl.Transaction tx, SurfaceControl leash) {
tx.setCornerRadius(leash, 0);
}

View File

@@ -76,10 +76,14 @@ public class RecentsAnimationControllerCompat {
* accordingly. This should be called before `finish`
* @param taskId Task id of the Activity in PiP mode.
* @param destinationBounds Bounds of the PiP window on home.
* @param windowCrop bounds to crop as part of final transform.
* @param float9 An array of 9 floats to be used as matrix transform.
*/
public void setFinishTaskBounds(int taskId, Rect destinationBounds) {
public void setFinishTaskBounds(int taskId, Rect destinationBounds, Rect windowCrop,
float[] float9) {
try {
mAnimationController.setFinishTaskBounds(taskId, destinationBounds);
mAnimationController.setFinishTaskBounds(taskId, destinationBounds, windowCrop,
float9);
} catch (RemoteException e) {
Log.d(TAG, "Failed to set finish task bounds", e);
}

View File

@@ -137,8 +137,11 @@ public class RemoteTransitionCompat implements Parcelable {
mWrapped.hideCurrentInputMethod();
}
@Override public void setFinishTaskBounds(int taskId, Rect destinationBounds) {
if (mWrapped != null) mWrapped.setFinishTaskBounds(taskId, destinationBounds);
@Override public void setFinishTaskBounds(int taskId, Rect destinationBounds,
Rect windowCrop, float[] float9) {
if (mWrapped != null) {
mWrapped.setFinishTaskBounds(taskId, destinationBounds, windowCrop, float9);
}
}
@Override public void finish(boolean toHome, boolean sendUserLeaveHint) {

View File

@@ -20,6 +20,10 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.graphics.Matrix.MSCALE_X;
import static android.graphics.Matrix.MSCALE_Y;
import static android.graphics.Matrix.MSKEW_X;
import static android.graphics.Matrix.MSKEW_Y;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
@@ -229,7 +233,8 @@ public class RecentsAnimationController implements DeathRecipient {
}
@Override
public void setFinishTaskBounds(int taskId, Rect destinationBounds) {
public void setFinishTaskBounds(int taskId, Rect destinationBounds, Rect windowCrop,
float[] float9) {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
"setFinishTaskBounds(%d): bounds=%s", taskId, destinationBounds);
final long token = Binder.clearCallingIdentity();
@@ -239,6 +244,8 @@ public class RecentsAnimationController implements DeathRecipient {
final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
if (taskAdapter.mTask.mTaskId == taskId) {
taskAdapter.mFinishBounds.set(destinationBounds);
taskAdapter.mFinishWindowCrop.set(windowCrop);
taskAdapter.mFinishTransform = float9;
break;
}
}
@@ -1084,6 +1091,9 @@ public class RecentsAnimationController implements DeathRecipient {
private final Rect mLocalBounds = new Rect();
// The bounds of the target when animation is finished
private final Rect mFinishBounds = new Rect();
// Bounds and transform for the final transaction.
private final Rect mFinishWindowCrop = new Rect();
private float[] mFinishTransform;
TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
mTask = task;
@@ -1120,13 +1130,31 @@ public class RecentsAnimationController implements DeathRecipient {
void onCleanup() {
if (!mFinishBounds.isEmpty()) {
// Apply any pending bounds changes
final SurfaceControl taskSurface = mTask.getSurfaceControl();
mTask.getPendingTransaction()
.setPosition(taskSurface, mFinishBounds.left, mFinishBounds.top)
.setWindowCrop(taskSurface, mFinishBounds.width(), mFinishBounds.height())
final SurfaceControl taskSurface = mTask.mSurfaceControl;
final Transaction pendingTransaction = mTask.getPendingTransaction();
if (mFinishTransform != null) {
pendingTransaction
.setMatrix(taskSurface,
mFinishTransform[MSCALE_X], mFinishTransform[MSKEW_Y],
mFinishTransform[MSKEW_X], mFinishTransform[MSCALE_Y]);
}
float left = mFinishBounds.left;
float top = mFinishBounds.top;
if (!mFinishWindowCrop.isEmpty()) {
pendingTransaction.setWindowCrop(taskSurface, mFinishWindowCrop);
if (mFinishTransform != null) {
// adjust the position for insets.
left -= mFinishWindowCrop.left * mFinishTransform[MSCALE_X];
top -= mFinishWindowCrop.top * mFinishTransform[MSCALE_Y];
}
}
pendingTransaction
.setPosition(taskSurface, left, top)
.apply();
mTask.mLastRecentsAnimationBounds.set(mFinishBounds);
// reset the variables
mFinishTransform = null;
mFinishWindowCrop.setEmpty();
mFinishBounds.setEmpty();
} else if (!mTask.isAttached()) {
// Apply the task's pending transaction in case it is detached and its transaction