Merge "Offset animation leash to the relative position" into sc-v2-dev am: 3dce047981

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15897562

Change-Id: I573a24d5b5c9cd0b7fa425b4a0ba8e601898dca4
This commit is contained in:
Chris Li
2021-09-28 09:51:14 +00:00
committed by Automerger Merge Worker
6 changed files with 105 additions and 28 deletions

View File

@@ -121,9 +121,11 @@ class TaskFragmentAnimationSpec {
* the second one is for the end leash. * the second one is for the end leash.
*/ */
Animation[] createChangeBoundsChangeAnimations(@NonNull RemoteAnimationTarget target) { Animation[] createChangeBoundsChangeAnimations(@NonNull RemoteAnimationTarget target) {
// Both start bounds and end bounds are in screen coordinates. We will post translate
// to the local coordinates in TaskFragmentAnimationAdapter#onAnimationUpdate
final Rect startBounds = target.startBounds; final Rect startBounds = target.startBounds;
final Rect parentBounds = target.taskInfo.configuration.windowConfiguration.getBounds(); final Rect parentBounds = target.taskInfo.configuration.windowConfiguration.getBounds();
final Rect endBounds = target.localBounds; final Rect endBounds = target.screenSpaceBounds;
float scaleX = ((float) startBounds.width()) / endBounds.width(); float scaleX = ((float) startBounds.width()) / endBounds.width();
float scaleY = ((float) startBounds.height()) / endBounds.height(); float scaleY = ((float) startBounds.height()) / endBounds.height();
// Start leash is a child of the end leash. Reverse the scale so that the start leash won't // Start leash is a child of the end leash. Reverse the scale so that the start leash won't

View File

@@ -1411,7 +1411,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
this.task = newTask; this.task = newTask;
if (shouldStartChangeTransition(newParent, oldParent)) { if (shouldStartChangeTransition(newParent, oldParent)) {
initializeChangeTransition(getBounds()); // The new parent and old parent may be in different position. Need to offset the
// animation surface to keep it in its original position.
initializeChangeTransition(getBounds(), newParent.getBounds());
} }
super.onParentChanged(newParent, oldParent); super.onParentChanged(newParent, oldParent);
@@ -9276,7 +9278,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
record.getMode(), record.mAdapter.mCapturedLeash, !fillsParent(), record.getMode(), record.mAdapter.mCapturedLeash, !fillsParent(),
new Rect(), insets, new Rect(), insets,
getPrefixOrderIndex(), record.mAdapter.mPosition, record.mAdapter.mLocalBounds, getPrefixOrderIndex(), record.mAdapter.mPosition, record.mAdapter.mLocalBounds,
record.mAdapter.mRootTaskBounds, task.getWindowConfiguration(), record.mAdapter.mEndBounds, task.getWindowConfiguration(),
false /*isNotInRecents*/, false /*isNotInRecents*/,
record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null, record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null,
record.mStartBounds, task.getTaskInfo(), checkEnterPictureInPictureAppOpsState()); record.mStartBounds, task.getTaskInfo(), checkEnterPictureInPictureAppOpsState());

View File

@@ -65,7 +65,6 @@ class RemoteAnimationController implements DeathRecipient {
new ArrayList<>(); new ArrayList<>();
@VisibleForTesting @VisibleForTesting
final ArrayList<NonAppWindowAnimationAdapter> mPendingNonAppAnimations = new ArrayList<>(); final ArrayList<NonAppWindowAnimationAdapter> mPendingNonAppAnimations = new ArrayList<>();
private final Rect mTmpRect = new Rect();
private final Handler mHandler; private final Handler mHandler;
private final Runnable mTimeoutRunnable = () -> cancelAnimation("timeoutRunnable"); private final Runnable mTimeoutRunnable = () -> cancelAnimation("timeoutRunnable");
@@ -85,18 +84,18 @@ class RemoteAnimationController implements DeathRecipient {
* Creates an animation record for each individual {@link WindowContainer}. * Creates an animation record for each individual {@link WindowContainer}.
* *
* @param windowContainer The windows to animate. * @param windowContainer The windows to animate.
* @param position The position app bounds, in screen coordinates. * @param position The position app bounds relative to its parent.
* @param localBounds The bounds of the app relative to its parent. * @param localBounds The bounds of the app relative to its parent.
* @param stackBounds The stack bounds of the app relative to position. * @param endBounds The end bounds after the transition, in screen coordinates.
* @param startBounds The stack bounds before the transition, in screen coordinates * @param startBounds The start bounds before the transition, in screen coordinates.
* @return The record representing animation(s) to run on the app. * @return The record representing animation(s) to run on the app.
*/ */
RemoteAnimationRecord createRemoteAnimationRecord(WindowContainer windowContainer, RemoteAnimationRecord createRemoteAnimationRecord(WindowContainer windowContainer,
Point position, Rect localBounds, Rect stackBounds, Rect startBounds) { Point position, Rect localBounds, Rect endBounds, Rect startBounds) {
ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAnimationAdapter(): container=%s", ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAnimationAdapter(): container=%s",
windowContainer); windowContainer);
final RemoteAnimationRecord adapters = new RemoteAnimationRecord(windowContainer, position, final RemoteAnimationRecord adapters = new RemoteAnimationRecord(windowContainer, position,
localBounds, stackBounds, startBounds); localBounds, endBounds, startBounds);
mPendingAnimations.add(adapters); mPendingAnimations.add(adapters);
return adapters; return adapters;
} }
@@ -405,16 +404,17 @@ class RemoteAnimationController implements DeathRecipient {
mStartBounds = new Rect(startBounds); mStartBounds = new Rect(startBounds);
mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds, mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds,
mStartBounds); mStartBounds);
mTmpRect.set(startBounds);
mTmpRect.offsetTo(0, 0);
if (mRemoteAnimationAdapter.getChangeNeedsSnapshot()) { if (mRemoteAnimationAdapter.getChangeNeedsSnapshot()) {
mThumbnailAdapter = final Rect thumbnailLocalBounds = new Rect(startBounds);
new RemoteAnimationAdapterWrapper(this, new Point(0, 0), localBounds, thumbnailLocalBounds.offsetTo(0, 0);
mTmpRect, new Rect()); // Snapshot is located at (0,0) of the animation leash. It doesn't have size
// change, so the startBounds is its end bounds, and no start bounds for it.
mThumbnailAdapter = new RemoteAnimationAdapterWrapper(this, new Point(0, 0),
thumbnailLocalBounds, startBounds, new Rect());
} }
} else { } else {
mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds, mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds,
new Rect(endPos.x, endPos.y, endBounds.right, endBounds.bottom)); new Rect());
mStartBounds = null; mStartBounds = null;
} }
} }
@@ -458,15 +458,15 @@ class RemoteAnimationController implements DeathRecipient {
private @AnimationType int mAnimationType; private @AnimationType int mAnimationType;
final Point mPosition = new Point(); final Point mPosition = new Point();
final Rect mLocalBounds; final Rect mLocalBounds;
final Rect mRootTaskBounds = new Rect(); final Rect mEndBounds = new Rect();
final Rect mStartBounds = new Rect(); final Rect mStartBounds = new Rect();
RemoteAnimationAdapterWrapper(RemoteAnimationRecord record, Point position, RemoteAnimationAdapterWrapper(RemoteAnimationRecord record, Point position,
Rect localBounds, Rect rootTaskBounds, Rect startBounds) { Rect localBounds, Rect endBounds, Rect startBounds) {
mRecord = record; mRecord = record;
mPosition.set(position.x, position.y); mPosition.set(position.x, position.y);
mLocalBounds = localBounds; mLocalBounds = localBounds;
mRootTaskBounds.set(rootTaskBounds); mEndBounds.set(endBounds);
mStartBounds.set(startBounds); mStartBounds.set(startBounds);
} }
@@ -480,12 +480,17 @@ class RemoteAnimationController implements DeathRecipient {
@AnimationType int type, OnAnimationFinishedCallback finishCallback) { @AnimationType int type, OnAnimationFinishedCallback finishCallback) {
ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation"); ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation");
// Restore position and stack crop until client has a chance to modify it.
if (mStartBounds.isEmpty()) { if (mStartBounds.isEmpty()) {
t.setPosition(animationLeash, 0, 0); // Restore position and stack crop until client has a chance to modify it.
t.setWindowCrop(animationLeash, -1, -1); t.setPosition(animationLeash, mPosition.x, mPosition.y);
t.setWindowCrop(animationLeash, mEndBounds.width(), mEndBounds.height());
} else { } else {
t.setPosition(animationLeash, mStartBounds.left, mStartBounds.top); // Offset the change animation leash to the relative start position in parent.
// (mPosition) is the relative end position in parent container.
// (mStartBounds - mEndBounds) is the position difference between start and end.
// (mPosition + mStartBounds - mEndBounds) will be the relative start position.
t.setPosition(animationLeash, mPosition.x + mStartBounds.left - mEndBounds.left,
mPosition.y + mStartBounds.top - mEndBounds.top);
t.setWindowCrop(animationLeash, mStartBounds.width(), mStartBounds.height()); t.setWindowCrop(animationLeash, mStartBounds.width(), mStartBounds.height());
} }
mCapturedLeash = animationLeash; mCapturedLeash = animationLeash;

View File

@@ -24,6 +24,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.graphics.GraphicBuffer; import android.graphics.GraphicBuffer;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.hardware.HardwareBuffer; import android.hardware.HardwareBuffer;
import android.view.Surface; import android.view.Surface;
@@ -70,13 +71,14 @@ class SurfaceFreezer {
* above the target surface) and then taking a snapshot and placing it over the target surface. * above the target surface) and then taking a snapshot and placing it over the target surface.
* *
* @param startBounds The original bounds (on screen) of the surface we are snapshotting. * @param startBounds The original bounds (on screen) of the surface we are snapshotting.
* @param relativePosition The related position of the snapshot surface to its parent.
*/ */
void freeze(SurfaceControl.Transaction t, Rect startBounds) { void freeze(SurfaceControl.Transaction t, Rect startBounds, Point relativePosition) {
mFreezeBounds.set(startBounds); mFreezeBounds.set(startBounds);
mLeash = SurfaceAnimator.createAnimationLeash(mAnimatable, mAnimatable.getSurfaceControl(), mLeash = SurfaceAnimator.createAnimationLeash(mAnimatable, mAnimatable.getSurfaceControl(),
t, ANIMATION_TYPE_SCREEN_ROTATION, startBounds.width(), startBounds.height(), t, ANIMATION_TYPE_SCREEN_ROTATION, startBounds.width(), startBounds.height(),
startBounds.left, startBounds.top, false /* hidden */, relativePosition.x, relativePosition.y, false /* hidden */,
mWmService.mTransactionFactory); mWmService.mTransactionFactory);
mAnimatable.onAnimationLeashCreated(t, mLeash); mAnimatable.onAnimationLeashCreated(t, mLeash);

View File

@@ -2623,11 +2623,20 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* 3. {@link ActivityRecord} is reparented into an organized {@link TaskFragment}. * 3. {@link ActivityRecord} is reparented into an organized {@link TaskFragment}.
* *
* This shouldn't be called on other {@link WindowContainer} unless there is a valid use case. * This shouldn't be called on other {@link WindowContainer} unless there is a valid use case.
*
* @param startBounds The original bounds (on screen) of the surface we are snapshotting.
* @param parentBounds The parent bounds (on screen) to calculate the animation surface
* position.
*/ */
void initializeChangeTransition(Rect startBounds) { void initializeChangeTransition(Rect startBounds, Rect parentBounds) {
mDisplayContent.prepareAppTransition(TRANSIT_CHANGE); mDisplayContent.prepareAppTransition(TRANSIT_CHANGE);
mDisplayContent.mChangingContainers.add(this); mDisplayContent.mChangingContainers.add(this);
mSurfaceFreezer.freeze(getSyncTransaction(), startBounds); mTmpPoint.set(startBounds.left - parentBounds.left, startBounds.top - parentBounds.top);
mSurfaceFreezer.freeze(getSyncTransaction(), startBounds, mTmpPoint);
}
void initializeChangeTransition(Rect startBounds) {
initializeChangeTransition(startBounds, getParent().getBounds());
} }
ArraySet<WindowContainer> getAnimationSources() { ArraySet<WindowContainer> getAnimationSources() {

View File

@@ -341,7 +341,8 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
verify(mMockTransaction).setWindowCrop( verify(mMockTransaction).setWindowCrop(
mMockLeash, app.startBounds.width(), app.startBounds.height()); mMockLeash, app.startBounds.width(), app.startBounds.height());
verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0); verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0);
verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, -1, -1); verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, app.startBounds.width(),
app.startBounds.height());
finishedCaptor.getValue().onAnimationFinished(); finishedCaptor.getValue().onAnimationFinished();
verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION), verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION),
@@ -394,7 +395,63 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
verify(mMockTransaction).setWindowCrop( verify(mMockTransaction).setWindowCrop(
mMockLeash, app.startBounds.width(), app.startBounds.height()); mMockLeash, app.startBounds.width(), app.startBounds.height());
verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0); verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0);
verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, -1, -1); verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, app.startBounds.width(),
app.startBounds.height());
finishedCaptor.getValue().onAnimationFinished();
verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION),
eq(record.mAdapter));
verify(mThumbnailFinishedCallback).onAnimationFinished(
eq(ANIMATION_TYPE_WINDOW_ANIMATION), eq(record.mThumbnailAdapter));
} finally {
mDisplayContent.mChangingContainers.clear();
}
}
@Test
public void testChangeToDifferentPosition() throws Exception {
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
mDisplayContent.mChangingContainers.add(win.mActivityRecord);
try {
final RemoteAnimationRecord record = mController.createRemoteAnimationRecord(
win.mActivityRecord, new Point(100, 100), null, new Rect(150, 150, 400, 400),
new Rect(50, 100, 150, 150));
assertNotNull(record.mThumbnailAdapter);
((AnimationAdapter) record.mAdapter)
.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION,
mFinishedCallback);
((AnimationAdapter) record.mThumbnailAdapter).startAnimation(mMockThumbnailLeash,
mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION, mThumbnailFinishedCallback);
mController.goodToGo(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE);
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<RemoteAnimationTarget[]> nonAppsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
ArgumentCaptor.forClass(IRemoteAnimationFinishedCallback.class);
verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE),
appsCaptor.capture(), wallpapersCaptor.capture(), nonAppsCaptor.capture(),
finishedCaptor.capture());
assertEquals(1, appsCaptor.getValue().length);
final RemoteAnimationTarget app = appsCaptor.getValue()[0];
assertEquals(RemoteAnimationTarget.MODE_CHANGING, app.mode);
assertEquals(new Point(100, 100), app.position);
assertEquals(new Rect(150, 150, 400, 400), app.sourceContainerBounds);
assertEquals(new Rect(50, 100, 150, 150), app.startBounds);
assertEquals(mMockLeash, app.leash);
assertEquals(mMockThumbnailLeash, app.startLeash);
assertEquals(false, app.isTranslucent);
verify(mMockTransaction).setPosition(
mMockLeash, app.position.x + app.startBounds.left - app.screenSpaceBounds.left,
app.position.y + app.startBounds.top - app.screenSpaceBounds.top);
verify(mMockTransaction).setWindowCrop(
mMockLeash, app.startBounds.width(), app.startBounds.height());
verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0);
verify(mMockTransaction).setWindowCrop(mMockThumbnailLeash, app.startBounds.width(),
app.startBounds.height());
finishedCaptor.getValue().onAnimationFinished(); finishedCaptor.getValue().onAnimationFinished();
verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION), verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION),