Loading services/core/java/com/android/server/wm/RootWindowContainer.java +1 −0 Original line number Diff line number Diff line Loading @@ -2098,6 +2098,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // from the client organizer, so the PIP activity can get the correct config // from the Task, and prevent conflict with the PipTaskOrganizer. tf.updateRequestedOverrideConfiguration(EMPTY); tf.updateRelativeEmbeddedBounds(); } }); rootTask.setWindowingMode(WINDOWING_MODE_PINNED); Loading services/core/java/com/android/server/wm/TaskFragment.java +52 −6 Original line number Diff line number Diff line Loading @@ -299,6 +299,14 @@ class TaskFragment extends WindowContainer<WindowContainer> { @Nullable private final IBinder mFragmentToken; /** * The bounds of the embedded TaskFragment relative to the parent Task. * {@code null} if it is not {@link #mIsEmbedded} * TODO(b/261785978) cleanup with legacy app transition */ @Nullable private final Rect mRelativeEmbeddedBounds; /** * Whether to delay the call to {@link #updateOrganizedTaskFragmentSurface()} when there is a * configuration change. Loading Loading @@ -381,6 +389,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { mRootWindowContainer = mAtmService.mRootWindowContainer; mCreatedByOrganizer = createdByOrganizer; mIsEmbedded = isEmbedded; mRelativeEmbeddedBounds = isEmbedded ? new Rect() : null; mTaskFragmentOrganizerController = mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController; mFragmentToken = fragmentToken; Loading Loading @@ -2419,16 +2428,53 @@ class TaskFragment extends WindowContainer<WindowContainer> { } } /** Whether we should prepare a transition for this {@link TaskFragment} bounds change. */ boolean shouldStartChangeTransition(Rect startBounds) { /** * Gets the relative bounds of this embedded TaskFragment. This should only be called on * embedded TaskFragment. */ @NonNull Rect getRelativeEmbeddedBounds() { if (mRelativeEmbeddedBounds == null) { throw new IllegalStateException("The TaskFragment is not embedded"); } return mRelativeEmbeddedBounds; } /** * Updates the record of the relative bounds of this embedded TaskFragment. This should only be * called when the embedded TaskFragment's override bounds are changed. * Returns {@code true} if the bounds is changed. */ void updateRelativeEmbeddedBounds() { // We only record the override bounds, which means it will not be changed when it is filling // Task, and resize with the parent. getRequestedOverrideBounds(mTmpBounds); getRelativePosition(mTmpPoint); mTmpBounds.offsetTo(mTmpPoint.x, mTmpPoint.y); mRelativeEmbeddedBounds.set(mTmpBounds); } /** * Updates the record of relative bounds of this embedded TaskFragment, and checks whether we * should prepare a transition for the bounds change. */ boolean shouldStartChangeTransition(@NonNull Rect absStartBounds, @NonNull Rect relStartBounds) { if (mTaskFragmentOrganizer == null || !canStartChangeTransition()) { return false; } // Only take snapshot if the bounds are resized. if (mTransitionController.isShellTransitionsEnabled()) { // For Shell transition, the change will be collected anyway, so only take snapshot when // the bounds are resized. final Rect endBounds = getConfiguration().windowConfiguration.getBounds(); return endBounds.width() != startBounds.width() || endBounds.height() != startBounds.height(); return endBounds.width() != absStartBounds.width() || endBounds.height() != absStartBounds.height(); } else { // For legacy transition, we need to trigger a change transition as long as the bounds // is changed, even if it is not resized. return !relStartBounds.equals(mRelativeEmbeddedBounds); } } /** Records the starting bounds of the closing organized TaskFragment. */ Loading services/core/java/com/android/server/wm/WindowOrganizerController.java +7 −5 Original line number Diff line number Diff line Loading @@ -149,7 +149,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub @VisibleForTesting final ArrayMap<IBinder, TaskFragment> mLaunchTaskFragments = new ArrayMap<>(); private final Rect mTmpBounds = new Rect(); private final Rect mTmpBounds0 = new Rect(); private final Rect mTmpBounds1 = new Rect(); WindowOrganizerController(ActivityTaskManagerService atm) { mService = atm; Loading Loading @@ -804,14 +805,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub // When the TaskFragment is resized, we may want to create a change transition for it, for // which we want to defer the surface update until we determine whether or not to start // change transition. mTmpBounds.set(taskFragment.getBounds()); mTmpBounds0.set(taskFragment.getBounds()); mTmpBounds1.set(taskFragment.getRelativeEmbeddedBounds()); taskFragment.deferOrganizedTaskFragmentSurfaceUpdate(); final int effects = applyChanges(taskFragment, c, errorCallbackToken); if (taskFragment.shouldStartChangeTransition(mTmpBounds)) { taskFragment.initializeChangeTransition(mTmpBounds); taskFragment.updateRelativeEmbeddedBounds(); if (taskFragment.shouldStartChangeTransition(mTmpBounds0, mTmpBounds1)) { taskFragment.initializeChangeTransition(mTmpBounds0); } taskFragment.continueOrganizedTaskFragmentSurfaceUpdate(); mTmpBounds.set(0, 0, 0, 0); return effects; } Loading services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +36 −2 Original line number Diff line number Diff line Loading @@ -106,19 +106,50 @@ public class TaskFragmentTest extends WindowTestsBase { verify(mTransaction).setWindowCrop(mLeash, 1000, 1000); } @Test public void testShouldStartChangeTransition_relativePositionChange() { mockSurfaceFreezerSnapshot(mTaskFragment.mSurfaceFreezer); final Rect startBounds = new Rect(0, 0, 500, 1000); final Rect endBounds = new Rect(500, 0, 1000, 1000); mTaskFragment.setBounds(startBounds); mTaskFragment.updateRelativeEmbeddedBounds(); doReturn(true).when(mTaskFragment).isVisible(); doReturn(true).when(mTaskFragment).isVisibleRequested(); // Do not resize, just change the relative position. final Rect relStartBounds = new Rect(mTaskFragment.getRelativeEmbeddedBounds()); mTaskFragment.setBounds(endBounds); mTaskFragment.updateRelativeEmbeddedBounds(); spyOn(mDisplayContent.mTransitionController); // For Shell transition, we don't want to take snapshot when the bounds are not resized doReturn(true).when(mDisplayContent.mTransitionController) .isShellTransitionsEnabled(); assertFalse(mTaskFragment.shouldStartChangeTransition(startBounds, relStartBounds)); // For legacy transition, we want to request a change transition even if it is just relative // bounds change. doReturn(false).when(mDisplayContent.mTransitionController) .isShellTransitionsEnabled(); assertTrue(mTaskFragment.shouldStartChangeTransition(startBounds, relStartBounds)); } @Test public void testStartChangeTransition_resetSurface() { mockSurfaceFreezerSnapshot(mTaskFragment.mSurfaceFreezer); final Rect startBounds = new Rect(0, 0, 1000, 1000); final Rect endBounds = new Rect(500, 500, 1000, 1000); mTaskFragment.setBounds(startBounds); mTaskFragment.updateRelativeEmbeddedBounds(); doReturn(true).when(mTaskFragment).isVisible(); doReturn(true).when(mTaskFragment).isVisibleRequested(); clearInvocations(mTransaction); final Rect relStartBounds = new Rect(mTaskFragment.getRelativeEmbeddedBounds()); mTaskFragment.deferOrganizedTaskFragmentSurfaceUpdate(); mTaskFragment.setBounds(endBounds); assertTrue(mTaskFragment.shouldStartChangeTransition(startBounds)); mTaskFragment.updateRelativeEmbeddedBounds(); assertTrue(mTaskFragment.shouldStartChangeTransition(startBounds, relStartBounds)); mTaskFragment.initializeChangeTransition(startBounds); mTaskFragment.continueOrganizedTaskFragmentSurfaceUpdate(); Loading Loading @@ -157,17 +188,20 @@ public class TaskFragmentTest extends WindowTestsBase { final Rect startBounds = new Rect(0, 0, 1000, 1000); final Rect endBounds = new Rect(500, 500, 1000, 1000); mTaskFragment.setBounds(startBounds); mTaskFragment.updateRelativeEmbeddedBounds(); doReturn(true).when(mTaskFragment).isVisible(); doReturn(true).when(mTaskFragment).isVisibleRequested(); final Rect relStartBounds = new Rect(mTaskFragment.getRelativeEmbeddedBounds()); final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy(); displayPolicy.screenTurnedOff(); assertFalse(mTaskFragment.okToAnimate()); mTaskFragment.setBounds(endBounds); mTaskFragment.updateRelativeEmbeddedBounds(); assertFalse(mTaskFragment.shouldStartChangeTransition(startBounds)); assertFalse(mTaskFragment.shouldStartChangeTransition(startBounds, relStartBounds)); } /** Loading Loading
services/core/java/com/android/server/wm/RootWindowContainer.java +1 −0 Original line number Diff line number Diff line Loading @@ -2098,6 +2098,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // from the client organizer, so the PIP activity can get the correct config // from the Task, and prevent conflict with the PipTaskOrganizer. tf.updateRequestedOverrideConfiguration(EMPTY); tf.updateRelativeEmbeddedBounds(); } }); rootTask.setWindowingMode(WINDOWING_MODE_PINNED); Loading
services/core/java/com/android/server/wm/TaskFragment.java +52 −6 Original line number Diff line number Diff line Loading @@ -299,6 +299,14 @@ class TaskFragment extends WindowContainer<WindowContainer> { @Nullable private final IBinder mFragmentToken; /** * The bounds of the embedded TaskFragment relative to the parent Task. * {@code null} if it is not {@link #mIsEmbedded} * TODO(b/261785978) cleanup with legacy app transition */ @Nullable private final Rect mRelativeEmbeddedBounds; /** * Whether to delay the call to {@link #updateOrganizedTaskFragmentSurface()} when there is a * configuration change. Loading Loading @@ -381,6 +389,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { mRootWindowContainer = mAtmService.mRootWindowContainer; mCreatedByOrganizer = createdByOrganizer; mIsEmbedded = isEmbedded; mRelativeEmbeddedBounds = isEmbedded ? new Rect() : null; mTaskFragmentOrganizerController = mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController; mFragmentToken = fragmentToken; Loading Loading @@ -2419,16 +2428,53 @@ class TaskFragment extends WindowContainer<WindowContainer> { } } /** Whether we should prepare a transition for this {@link TaskFragment} bounds change. */ boolean shouldStartChangeTransition(Rect startBounds) { /** * Gets the relative bounds of this embedded TaskFragment. This should only be called on * embedded TaskFragment. */ @NonNull Rect getRelativeEmbeddedBounds() { if (mRelativeEmbeddedBounds == null) { throw new IllegalStateException("The TaskFragment is not embedded"); } return mRelativeEmbeddedBounds; } /** * Updates the record of the relative bounds of this embedded TaskFragment. This should only be * called when the embedded TaskFragment's override bounds are changed. * Returns {@code true} if the bounds is changed. */ void updateRelativeEmbeddedBounds() { // We only record the override bounds, which means it will not be changed when it is filling // Task, and resize with the parent. getRequestedOverrideBounds(mTmpBounds); getRelativePosition(mTmpPoint); mTmpBounds.offsetTo(mTmpPoint.x, mTmpPoint.y); mRelativeEmbeddedBounds.set(mTmpBounds); } /** * Updates the record of relative bounds of this embedded TaskFragment, and checks whether we * should prepare a transition for the bounds change. */ boolean shouldStartChangeTransition(@NonNull Rect absStartBounds, @NonNull Rect relStartBounds) { if (mTaskFragmentOrganizer == null || !canStartChangeTransition()) { return false; } // Only take snapshot if the bounds are resized. if (mTransitionController.isShellTransitionsEnabled()) { // For Shell transition, the change will be collected anyway, so only take snapshot when // the bounds are resized. final Rect endBounds = getConfiguration().windowConfiguration.getBounds(); return endBounds.width() != startBounds.width() || endBounds.height() != startBounds.height(); return endBounds.width() != absStartBounds.width() || endBounds.height() != absStartBounds.height(); } else { // For legacy transition, we need to trigger a change transition as long as the bounds // is changed, even if it is not resized. return !relStartBounds.equals(mRelativeEmbeddedBounds); } } /** Records the starting bounds of the closing organized TaskFragment. */ Loading
services/core/java/com/android/server/wm/WindowOrganizerController.java +7 −5 Original line number Diff line number Diff line Loading @@ -149,7 +149,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub @VisibleForTesting final ArrayMap<IBinder, TaskFragment> mLaunchTaskFragments = new ArrayMap<>(); private final Rect mTmpBounds = new Rect(); private final Rect mTmpBounds0 = new Rect(); private final Rect mTmpBounds1 = new Rect(); WindowOrganizerController(ActivityTaskManagerService atm) { mService = atm; Loading Loading @@ -804,14 +805,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub // When the TaskFragment is resized, we may want to create a change transition for it, for // which we want to defer the surface update until we determine whether or not to start // change transition. mTmpBounds.set(taskFragment.getBounds()); mTmpBounds0.set(taskFragment.getBounds()); mTmpBounds1.set(taskFragment.getRelativeEmbeddedBounds()); taskFragment.deferOrganizedTaskFragmentSurfaceUpdate(); final int effects = applyChanges(taskFragment, c, errorCallbackToken); if (taskFragment.shouldStartChangeTransition(mTmpBounds)) { taskFragment.initializeChangeTransition(mTmpBounds); taskFragment.updateRelativeEmbeddedBounds(); if (taskFragment.shouldStartChangeTransition(mTmpBounds0, mTmpBounds1)) { taskFragment.initializeChangeTransition(mTmpBounds0); } taskFragment.continueOrganizedTaskFragmentSurfaceUpdate(); mTmpBounds.set(0, 0, 0, 0); return effects; } Loading
services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +36 −2 Original line number Diff line number Diff line Loading @@ -106,19 +106,50 @@ public class TaskFragmentTest extends WindowTestsBase { verify(mTransaction).setWindowCrop(mLeash, 1000, 1000); } @Test public void testShouldStartChangeTransition_relativePositionChange() { mockSurfaceFreezerSnapshot(mTaskFragment.mSurfaceFreezer); final Rect startBounds = new Rect(0, 0, 500, 1000); final Rect endBounds = new Rect(500, 0, 1000, 1000); mTaskFragment.setBounds(startBounds); mTaskFragment.updateRelativeEmbeddedBounds(); doReturn(true).when(mTaskFragment).isVisible(); doReturn(true).when(mTaskFragment).isVisibleRequested(); // Do not resize, just change the relative position. final Rect relStartBounds = new Rect(mTaskFragment.getRelativeEmbeddedBounds()); mTaskFragment.setBounds(endBounds); mTaskFragment.updateRelativeEmbeddedBounds(); spyOn(mDisplayContent.mTransitionController); // For Shell transition, we don't want to take snapshot when the bounds are not resized doReturn(true).when(mDisplayContent.mTransitionController) .isShellTransitionsEnabled(); assertFalse(mTaskFragment.shouldStartChangeTransition(startBounds, relStartBounds)); // For legacy transition, we want to request a change transition even if it is just relative // bounds change. doReturn(false).when(mDisplayContent.mTransitionController) .isShellTransitionsEnabled(); assertTrue(mTaskFragment.shouldStartChangeTransition(startBounds, relStartBounds)); } @Test public void testStartChangeTransition_resetSurface() { mockSurfaceFreezerSnapshot(mTaskFragment.mSurfaceFreezer); final Rect startBounds = new Rect(0, 0, 1000, 1000); final Rect endBounds = new Rect(500, 500, 1000, 1000); mTaskFragment.setBounds(startBounds); mTaskFragment.updateRelativeEmbeddedBounds(); doReturn(true).when(mTaskFragment).isVisible(); doReturn(true).when(mTaskFragment).isVisibleRequested(); clearInvocations(mTransaction); final Rect relStartBounds = new Rect(mTaskFragment.getRelativeEmbeddedBounds()); mTaskFragment.deferOrganizedTaskFragmentSurfaceUpdate(); mTaskFragment.setBounds(endBounds); assertTrue(mTaskFragment.shouldStartChangeTransition(startBounds)); mTaskFragment.updateRelativeEmbeddedBounds(); assertTrue(mTaskFragment.shouldStartChangeTransition(startBounds, relStartBounds)); mTaskFragment.initializeChangeTransition(startBounds); mTaskFragment.continueOrganizedTaskFragmentSurfaceUpdate(); Loading Loading @@ -157,17 +188,20 @@ public class TaskFragmentTest extends WindowTestsBase { final Rect startBounds = new Rect(0, 0, 1000, 1000); final Rect endBounds = new Rect(500, 500, 1000, 1000); mTaskFragment.setBounds(startBounds); mTaskFragment.updateRelativeEmbeddedBounds(); doReturn(true).when(mTaskFragment).isVisible(); doReturn(true).when(mTaskFragment).isVisibleRequested(); final Rect relStartBounds = new Rect(mTaskFragment.getRelativeEmbeddedBounds()); final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy(); displayPolicy.screenTurnedOff(); assertFalse(mTaskFragment.okToAnimate()); mTaskFragment.setBounds(endBounds); mTaskFragment.updateRelativeEmbeddedBounds(); assertFalse(mTaskFragment.shouldStartChangeTransition(startBounds)); assertFalse(mTaskFragment.shouldStartChangeTransition(startBounds, relStartBounds)); } /** Loading