From ae9155a47bdb9f1cb58466decc8749b092dc1ea9 Mon Sep 17 00:00:00 2001 From: Chris Li Date: Wed, 29 Sep 2021 18:32:24 +0800 Subject: [PATCH] Change the activity reparent to animate at TaskFragment level. Before, we are animating at activity level, but that wouldn't work after we set the TaskFragment window crop. Now, we animate the change transition on the TaskFragment level instead. Bug: 196173550 Test: atest WmTests:AppTransitionTests #testActivityRecordReparentToTaskFragment Change-Id: Ie777dc8bf438300f59f8a2565cd999c6a29561d8 --- .../com/android/server/wm/ActivityRecord.java | 5 ++--- .../server/wm/AppTransitionController.java | 3 --- .../com/android/server/wm/SurfaceFreezer.java | 7 +++++-- .../com/android/server/wm/WindowContainer.java | 18 +++++++++++------- .../android/server/wm/AppTransitionTests.java | 13 ++++++++++++- 5 files changed, 30 insertions(+), 16 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index db44dd8f70d17..c1fcf71b38d28 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1411,9 +1411,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A this.task = newTask; if (shouldStartChangeTransition(newParent, oldParent)) { - // 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()); + // Animate change transition on TaskFragment level to get the correct window crop. + newParent.initializeChangeTransition(getBounds(), getSurfaceControl()); } super.onParentChanged(newParent, oldParent); diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 82377b34d22a5..3fc785a254544 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -343,9 +343,6 @@ public class AppTransitionController { switch (changingType) { case TYPE_TASK: return TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; - case TYPE_ACTIVITY: - // ActivityRecord is put in a change transition only when it is reparented - // to an organized TaskFragment. See ActivityRecord#shouldStartChangeTransition. case TYPE_TASK_FRAGMENT: return TRANSIT_OLD_TASK_FRAGMENT_CHANGE; default: diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java index 9c4f6f574487f..89986cefb207c 100644 --- a/services/core/java/com/android/server/wm/SurfaceFreezer.java +++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java @@ -72,8 +72,11 @@ class SurfaceFreezer { * * @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. + * @param freezeTarget The surface to take snapshot from. If {@code null}, we will take a + * snapshot from the {@link #mAnimatable} surface. */ - void freeze(SurfaceControl.Transaction t, Rect startBounds, Point relativePosition) { + void freeze(SurfaceControl.Transaction t, Rect startBounds, Point relativePosition, + @Nullable SurfaceControl freezeTarget) { mFreezeBounds.set(startBounds); mLeash = SurfaceAnimator.createAnimationLeash(mAnimatable, mAnimatable.getSurfaceControl(), @@ -82,7 +85,7 @@ class SurfaceFreezer { mWmService.mTransactionFactory); mAnimatable.onAnimationLeashCreated(t, mLeash); - SurfaceControl freezeTarget = mAnimatable.getFreezeSnapshotTarget(); + freezeTarget = freezeTarget != null ? freezeTarget : mAnimatable.getFreezeSnapshotTarget(); if (freezeTarget != null) { SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = createSnapshotBuffer( freezeTarget, startBounds); diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 0bc3712d79468..38e20555f236f 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -2620,23 +2620,27 @@ class WindowContainer extends ConfigurationContainer< * For now, this will only be called for the following cases: * 1. {@link Task} is changing windowing mode between fullscreen and freeform. * 2. {@link TaskFragment} is organized and is changing window bounds. - * 3. {@link ActivityRecord} is reparented into an organized {@link TaskFragment}. + * 3. {@link ActivityRecord} is reparented into an organized {@link TaskFragment}. (The + * transition will happen on the {@link TaskFragment} for this case). * - * 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. + * @param freezeTarget The surface to take snapshot from. If {@code null}, we will take a + * snapshot from {@link #getFreezeSnapshotTarget()}. */ - void initializeChangeTransition(Rect startBounds, Rect parentBounds) { + void initializeChangeTransition(Rect startBounds, @Nullable SurfaceControl freezeTarget) { mDisplayContent.prepareAppTransition(TRANSIT_CHANGE); mDisplayContent.mChangingContainers.add(this); + // Calculate the relative position in parent container. + final Rect parentBounds = getParent().getBounds(); mTmpPoint.set(startBounds.left - parentBounds.left, startBounds.top - parentBounds.top); - mSurfaceFreezer.freeze(getSyncTransaction(), startBounds, mTmpPoint); + mSurfaceFreezer.freeze(getSyncTransaction(), startBounds, mTmpPoint, freezeTarget); } void initializeChangeTransition(Rect startBounds) { - initializeChangeTransition(startBounds, getParent().getBounds()); + initializeChangeTransition(startBounds, null /* freezeTarget */); } ArraySet getAnimationSources() { diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index 405d714256ab9..fb8bc7be38cea 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -35,6 +35,8 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static org.junit.Assert.assertEquals; @@ -42,6 +44,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; import android.graphics.Rect; import android.os.Binder; @@ -54,6 +57,7 @@ import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; +import android.view.SurfaceControl; import android.view.WindowManager; import android.window.ITaskFragmentOrganizer; import android.window.TaskFragmentOrganizer; @@ -397,7 +401,9 @@ public class AppTransitionTests extends WindowTestsBase { @Test public void testActivityRecordReparentToTaskFragment() { final ActivityRecord activity = createActivityRecord(mDc); + final SurfaceControl activityLeash = mock(SurfaceControl.class); activity.setVisibility(true); + activity.setSurfaceControl(activityLeash); final Task task = activity.getTask(); // Add a TaskFragment of half of the Task size. @@ -412,15 +418,20 @@ public class AppTransitionTests extends WindowTestsBase { final Rect taskBounds = new Rect(); task.getBounds(taskBounds); taskFragment.setBounds(0, 0, taskBounds.right / 2, taskBounds.bottom); + spyOn(taskFragment); assertTrue(mDc.mChangingContainers.isEmpty()); assertFalse(mDc.mAppTransition.isTransitionSet()); // Schedule app transition when reparent activity to a TaskFragment of different size. + final Rect startBounds = new Rect(activity.getBounds()); activity.reparent(taskFragment, POSITION_TOP); - assertTrue(mDc.mChangingContainers.contains(activity)); + // It should transit at TaskFragment level with snapshot on the activity surface. + verify(taskFragment).initializeChangeTransition(activity.getBounds(), activityLeash); + assertTrue(mDc.mChangingContainers.contains(taskFragment)); assertTrue(mDc.mAppTransition.containsTransitRequest(TRANSIT_CHANGE)); + assertEquals(startBounds, taskFragment.mSurfaceFreezer.mFreezeBounds); } private class TestRemoteAnimationRunner implements IRemoteAnimationRunner {