Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java +29 −13 Original line number Original line Diff line number Diff line Loading @@ -154,7 +154,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { activityOptions); activityOptions); // Set adjacent to each other so that the containers below will be invisible. // Set adjacent to each other so that the containers below will be invisible. setAdjacentTaskFragments(wct, launchingFragmentToken, secondaryFragmentToken, rule); setAdjacentTaskFragmentsWithRule(wct, launchingFragmentToken, secondaryFragmentToken, rule); setCompanionTaskFragment(wct, launchingFragmentToken, secondaryFragmentToken, rule, setCompanionTaskFragment(wct, launchingFragmentToken, secondaryFragmentToken, rule, false /* isStacked */); false /* isStacked */); } } Loading @@ -167,7 +167,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { void expandTaskFragment(@NonNull WindowContainerTransaction wct, void expandTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken) { @NonNull IBinder fragmentToken) { resizeTaskFragment(wct, fragmentToken, new Rect()); resizeTaskFragment(wct, fragmentToken, new Rect()); setAdjacentTaskFragments(wct, fragmentToken, null /* secondary */, null /* splitRule */); clearAdjacentTaskFragments(wct, fragmentToken); updateWindowingMode(wct, fragmentToken, WINDOWING_MODE_UNDEFINED); updateWindowingMode(wct, fragmentToken, WINDOWING_MODE_UNDEFINED); updateAnimationParams(wct, fragmentToken, TaskFragmentAnimationParams.DEFAULT); updateAnimationParams(wct, fragmentToken, TaskFragmentAnimationParams.DEFAULT); } } Loading Loading @@ -238,26 +238,37 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { wct.reparentActivityToTaskFragment(fragmentToken, reparentActivityToken); wct.reparentActivityToTaskFragment(fragmentToken, reparentActivityToken); } } void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct, /** @NonNull IBinder primary, @Nullable IBinder secondary, @Nullable SplitRule splitRule) { * Sets the two given TaskFragments as adjacent to each other with respecting the given if (secondary == null) { * {@link SplitRule} for {@link WindowContainerTransaction.TaskFragmentAdjacentParams}. wct.clearAdjacentTaskFragments(primary); */ return; void setAdjacentTaskFragmentsWithRule(@NonNull WindowContainerTransaction wct, } @NonNull IBinder primary, @NonNull IBinder secondary, @NonNull SplitRule splitRule) { WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams = null; WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams = null; final boolean finishSecondaryWithPrimary = final boolean finishSecondaryWithPrimary = splitRule != null && SplitContainer.shouldFinishSecondaryWithPrimary(splitRule); SplitContainer.shouldFinishSecondaryWithPrimary(splitRule); final boolean finishPrimaryWithSecondary = final boolean finishPrimaryWithSecondary = splitRule != null && SplitContainer.shouldFinishPrimaryWithSecondary(splitRule); SplitContainer.shouldFinishPrimaryWithSecondary(splitRule); if (finishSecondaryWithPrimary || finishPrimaryWithSecondary) { if (finishSecondaryWithPrimary || finishPrimaryWithSecondary) { adjacentParams = new WindowContainerTransaction.TaskFragmentAdjacentParams(); adjacentParams = new WindowContainerTransaction.TaskFragmentAdjacentParams(); adjacentParams.setShouldDelayPrimaryLastActivityRemoval(finishSecondaryWithPrimary); adjacentParams.setShouldDelayPrimaryLastActivityRemoval(finishSecondaryWithPrimary); adjacentParams.setShouldDelaySecondaryLastActivityRemoval(finishPrimaryWithSecondary); adjacentParams.setShouldDelaySecondaryLastActivityRemoval(finishPrimaryWithSecondary); } } setAdjacentTaskFragments(wct, primary, secondary, adjacentParams); } void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @NonNull IBinder secondary, @Nullable WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams) { wct.setAdjacentTaskFragments(primary, secondary, adjacentParams); wct.setAdjacentTaskFragments(primary, secondary, adjacentParams); } } void clearAdjacentTaskFragments(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken) { // Clear primary will also clear secondary. wct.clearAdjacentTaskFragments(fragmentToken); } void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct, void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @NonNull IBinder secondary, @NonNull SplitRule splitRule, @NonNull IBinder primary, @NonNull IBinder secondary, @NonNull SplitRule splitRule, boolean isStacked) { boolean isStacked) { Loading @@ -268,7 +279,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { } else { } else { finishPrimaryWithSecondary = shouldFinishPrimaryWithSecondary(splitRule); finishPrimaryWithSecondary = shouldFinishPrimaryWithSecondary(splitRule); } } wct.setCompanionTaskFragment(primary, finishPrimaryWithSecondary ? secondary : null); setCompanionTaskFragment(wct, primary, finishPrimaryWithSecondary ? secondary : null); final boolean finishSecondaryWithPrimary; final boolean finishSecondaryWithPrimary; if (isStacked) { if (isStacked) { Loading @@ -277,7 +288,12 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { } else { } else { finishSecondaryWithPrimary = shouldFinishSecondaryWithPrimary(splitRule); finishSecondaryWithPrimary = shouldFinishSecondaryWithPrimary(splitRule); } } wct.setCompanionTaskFragment(secondary, finishSecondaryWithPrimary ? primary : null); setCompanionTaskFragment(wct, secondary, finishSecondaryWithPrimary ? primary : null); } void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @Nullable IBinder secondary) { wct.setCompanionTaskFragment(primary, secondary); } } void resizeTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken, void resizeTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken, Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +3 −0 Original line number Original line Diff line number Diff line Loading @@ -525,6 +525,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // All overrides will be cleanup. // All overrides will be cleanup. container.setLastRequestedBounds(null /* bounds */); container.setLastRequestedBounds(null /* bounds */); container.setLastRequestedWindowingMode(WINDOWING_MODE_UNDEFINED); container.setLastRequestedWindowingMode(WINDOWING_MODE_UNDEFINED); container.clearLastAdjacentTaskFragment(); container.setLastCompanionTaskFragment(null /* fragmentToken */); container.setLastRequestAnimationParams(TaskFragmentAnimationParams.DEFAULT); cleanupForEnterPip(wct, container); cleanupForEnterPip(wct, container); } else if (wasInPip) { } else if (wasInPip) { // Exit PIP. // Exit PIP. Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +64 −7 Original line number Original line Diff line number Diff line Loading @@ -385,10 +385,9 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { // secondaryContainer could not be finished. // secondaryContainer could not be finished. boolean isStacked = !shouldShowSplit(splitAttributes); boolean isStacked = !shouldShowSplit(splitAttributes); if (isStacked) { if (isStacked) { setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(), clearAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken()); null /* secondary */, null /* splitRule */); } else { } else { setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(), setAdjacentTaskFragmentsWithRule(wct, primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken(), splitRule); secondaryContainer.getTaskFragmentToken(), splitRule); } } setCompanionTaskFragment(wct, primaryContainer.getTaskFragmentToken(), setCompanionTaskFragment(wct, primaryContainer.getTaskFragmentToken(), Loading Loading @@ -425,7 +424,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { fragmentOptions.getFragmentToken()); fragmentOptions.getFragmentToken()); if (container == null) { if (container == null) { throw new IllegalStateException( throw new IllegalStateException( "Creating a task fragment that is not registered with controller."); "Creating a TaskFragment that is not registered with controller."); } } container.setLastRequestedBounds(fragmentOptions.getInitialRelativeBounds()); container.setLastRequestedBounds(fragmentOptions.getInitialRelativeBounds()); Loading @@ -439,7 +438,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { TaskFragmentContainer container = mController.getContainer(fragmentToken); TaskFragmentContainer container = mController.getContainer(fragmentToken); if (container == null) { if (container == null) { throw new IllegalStateException( throw new IllegalStateException( "Resizing a task fragment that is not registered with controller."); "Resizing a TaskFragment that is not registered with controller."); } } if (container.areLastRequestedBoundsEqual(relBounds)) { if (container.areLastRequestedBoundsEqual(relBounds)) { Loading @@ -456,7 +455,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @NonNull IBinder fragmentToken, @WindowingMode int windowingMode) { @NonNull IBinder fragmentToken, @WindowingMode int windowingMode) { final TaskFragmentContainer container = mController.getContainer(fragmentToken); final TaskFragmentContainer container = mController.getContainer(fragmentToken); if (container == null) { if (container == null) { throw new IllegalStateException("Setting windowing mode for a task fragment that is" throw new IllegalStateException("Setting windowing mode for a TaskFragment that is" + " not registered with controller."); + " not registered with controller."); } } Loading @@ -474,7 +473,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @NonNull IBinder fragmentToken, @NonNull TaskFragmentAnimationParams animationParams) { @NonNull IBinder fragmentToken, @NonNull TaskFragmentAnimationParams animationParams) { final TaskFragmentContainer container = mController.getContainer(fragmentToken); final TaskFragmentContainer container = mController.getContainer(fragmentToken); if (container == null) { if (container == null) { throw new IllegalStateException("Setting animation params for a task fragment that is" throw new IllegalStateException("Setting animation params for a TaskFragment that is" + " not registered with controller."); + " not registered with controller."); } } Loading @@ -487,6 +486,64 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { super.updateAnimationParams(wct, fragmentToken, animationParams); super.updateAnimationParams(wct, fragmentToken, animationParams); } } @Override void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @NonNull IBinder secondary, @Nullable WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams) { final TaskFragmentContainer primaryContainer = mController.getContainer(primary); final TaskFragmentContainer secondaryContainer = mController.getContainer(secondary); if (primaryContainer == null || secondaryContainer == null) { throw new IllegalStateException("setAdjacentTaskFragments on TaskFragment that is" + " not registered with controller."); } if (primaryContainer.isLastAdjacentTaskFragmentEqual(secondary, adjacentParams) && secondaryContainer.isLastAdjacentTaskFragmentEqual(primary, adjacentParams)) { // Return early if the same adjacent TaskFragments were already requested return; } primaryContainer.setLastAdjacentTaskFragment(secondary, adjacentParams); secondaryContainer.setLastAdjacentTaskFragment(primary, adjacentParams); super.setAdjacentTaskFragments(wct, primary, secondary, adjacentParams); } @Override void clearAdjacentTaskFragments(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken) { final TaskFragmentContainer container = mController.getContainer(fragmentToken); if (container == null) { throw new IllegalStateException("clearAdjacentTaskFragments on TaskFragment that is" + " not registered with controller."); } if (container.isLastAdjacentTaskFragmentEqual(null /* fragmentToken*/, null /* params */)) { // Return early if no adjacent TaskFragment was yet requested return; } container.clearLastAdjacentTaskFragment(); super.clearAdjacentTaskFragments(wct, fragmentToken); } @Override void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @Nullable IBinder secondary) { final TaskFragmentContainer container = mController.getContainer(primary); if (container == null) { throw new IllegalStateException("setCompanionTaskFragment on TaskFragment that is" + " not registered with controller."); } if (container.isLastCompanionTaskFragmentEqual(secondary)) { // Return early if the same companion TaskFragment was already requested return; } container.setLastCompanionTaskFragment(secondary); super.setCompanionTaskFragment(wct, primary, secondary); } /** /** * Expands the split container if the current split bounds are smaller than the Activity or * Expands the split container if the current split bounds are smaller than the Activity or * Intent that is added to the container. * Intent that is added to the container. Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +82 −5 Original line number Original line Diff line number Diff line Loading @@ -40,6 +40,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Collections; import java.util.Iterator; import java.util.Iterator; import java.util.List; import java.util.List; import java.util.Objects; /** /** * Client-side container for a stack of activities. Corresponds to an instance of TaskFragment * Client-side container for a stack of activities. Corresponds to an instance of TaskFragment Loading Loading @@ -116,6 +117,27 @@ class TaskFragmentContainer { @NonNull @NonNull private TaskFragmentAnimationParams mLastAnimationParams = TaskFragmentAnimationParams.DEFAULT; private TaskFragmentAnimationParams mLastAnimationParams = TaskFragmentAnimationParams.DEFAULT; /** * TaskFragment token that was requested last via * {@link android.window.TaskFragmentOperation#OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS}. */ @Nullable private IBinder mLastAdjacentTaskFragment; /** * {@link WindowContainerTransaction.TaskFragmentAdjacentParams} token that was requested last * via {@link android.window.TaskFragmentOperation#OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS}. */ @Nullable private WindowContainerTransaction.TaskFragmentAdjacentParams mLastAdjacentParams; /** * TaskFragment token that was requested last via * {@link android.window.TaskFragmentOperation#OP_TYPE_SET_COMPANION_TASK_FRAGMENT}. */ @Nullable private IBinder mLastCompanionTaskFragment; /** /** * When the TaskFragment has appeared in server, but is empty, we should remove the TaskFragment * When the TaskFragment has appeared in server, but is empty, we should remove the TaskFragment * if it is still empty after the timeout. * if it is still empty after the timeout. Loading Loading @@ -591,6 +613,7 @@ class TaskFragmentContainer { /** /** * Checks if last requested bounds are equal to the provided value. * Checks if last requested bounds are equal to the provided value. * The requested bounds are relative bounds in parent coordinate. * The requested bounds are relative bounds in parent coordinate. * @see WindowContainerTransaction#setRelativeBounds */ */ boolean areLastRequestedBoundsEqual(@Nullable Rect relBounds) { boolean areLastRequestedBoundsEqual(@Nullable Rect relBounds) { return (relBounds == null && mLastRequestedBounds.isEmpty()) return (relBounds == null && mLastRequestedBounds.isEmpty()) Loading @@ -600,6 +623,7 @@ class TaskFragmentContainer { /** /** * Updates the last requested bounds. * Updates the last requested bounds. * The requested bounds are relative bounds in parent coordinate. * The requested bounds are relative bounds in parent coordinate. * @see WindowContainerTransaction#setRelativeBounds */ */ void setLastRequestedBounds(@Nullable Rect relBounds) { void setLastRequestedBounds(@Nullable Rect relBounds) { if (relBounds == null) { if (relBounds == null) { Loading @@ -609,13 +633,9 @@ class TaskFragmentContainer { } } } } @NonNull Rect getLastRequestedBounds() { return mLastRequestedBounds; } /** /** * Checks if last requested windowing mode is equal to the provided value. * Checks if last requested windowing mode is equal to the provided value. * @see WindowContainerTransaction#setWindowingMode */ */ boolean isLastRequestedWindowingModeEqual(@WindowingMode int windowingMode) { boolean isLastRequestedWindowingModeEqual(@WindowingMode int windowingMode) { return mLastRequestedWindowingMode == windowingMode; return mLastRequestedWindowingMode == windowingMode; Loading @@ -623,6 +643,7 @@ class TaskFragmentContainer { /** /** * Updates the last requested windowing mode. * Updates the last requested windowing mode. * @see WindowContainerTransaction#setWindowingMode */ */ void setLastRequestedWindowingMode(@WindowingMode int windowingModes) { void setLastRequestedWindowingMode(@WindowingMode int windowingModes) { mLastRequestedWindowingMode = windowingModes; mLastRequestedWindowingMode = windowingModes; Loading @@ -630,6 +651,7 @@ class TaskFragmentContainer { /** /** * Checks if last requested {@link TaskFragmentAnimationParams} are equal to the provided value. * Checks if last requested {@link TaskFragmentAnimationParams} are equal to the provided value. * @see android.window.TaskFragmentOperation#OP_TYPE_SET_ANIMATION_PARAMS */ */ boolean areLastRequestedAnimationParamsEqual( boolean areLastRequestedAnimationParamsEqual( @NonNull TaskFragmentAnimationParams animationParams) { @NonNull TaskFragmentAnimationParams animationParams) { Loading @@ -638,11 +660,66 @@ class TaskFragmentContainer { /** /** * Updates the last requested {@link TaskFragmentAnimationParams}. * Updates the last requested {@link TaskFragmentAnimationParams}. * @see android.window.TaskFragmentOperation#OP_TYPE_SET_ANIMATION_PARAMS */ */ void setLastRequestAnimationParams(@NonNull TaskFragmentAnimationParams animationParams) { void setLastRequestAnimationParams(@NonNull TaskFragmentAnimationParams animationParams) { mLastAnimationParams = animationParams; mLastAnimationParams = animationParams; } } /** * Checks if last requested adjacent TaskFragment token and params are equal to the provided * values. * @see android.window.TaskFragmentOperation#OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS * @see android.window.TaskFragmentOperation#OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS */ boolean isLastAdjacentTaskFragmentEqual(@Nullable IBinder fragmentToken, @Nullable WindowContainerTransaction.TaskFragmentAdjacentParams params) { return Objects.equals(mLastAdjacentTaskFragment, fragmentToken) && Objects.equals(mLastAdjacentParams, params); } /** * Updates the last requested adjacent TaskFragment token and params. * @see android.window.TaskFragmentOperation#OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS */ void setLastAdjacentTaskFragment(@NonNull IBinder fragmentToken, @NonNull WindowContainerTransaction.TaskFragmentAdjacentParams params) { mLastAdjacentTaskFragment = fragmentToken; mLastAdjacentParams = params; } /** * Clears the last requested adjacent TaskFragment token and params. * @see android.window.TaskFragmentOperation#OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS */ void clearLastAdjacentTaskFragment() { final TaskFragmentContainer lastAdjacentTaskFragment = mLastAdjacentTaskFragment != null ? mController.getContainer(mLastAdjacentTaskFragment) : null; mLastAdjacentTaskFragment = null; mLastAdjacentParams = null; if (lastAdjacentTaskFragment != null) { // Clear the previous adjacent TaskFragment as well. lastAdjacentTaskFragment.clearLastAdjacentTaskFragment(); } } /** * Checks if last requested companion TaskFragment token is equal to the provided value. * @see android.window.TaskFragmentOperation#OP_TYPE_SET_COMPANION_TASK_FRAGMENT */ boolean isLastCompanionTaskFragmentEqual(@Nullable IBinder fragmentToken) { return Objects.equals(mLastCompanionTaskFragment, fragmentToken); } /** * Updates the last requested companion TaskFragment token. * @see android.window.TaskFragmentOperation#OP_TYPE_SET_COMPANION_TASK_FRAGMENT */ void setLastCompanionTaskFragment(@Nullable IBinder fragmentToken) { mLastCompanionTaskFragment = fragmentToken; } /** Gets the parent leaf Task id. */ /** Gets the parent leaf Task id. */ int getTaskId() { int getTaskId() { return mTaskContainer.getTaskId(); return mTaskContainer.getTaskId(); Loading libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java +58 −0 Original line number Original line Diff line number Diff line Loading @@ -176,6 +176,64 @@ public class SplitPresenterTest { verify(mTransaction, never()).setWindowingMode(any(), anyInt()); verify(mTransaction, never()).setWindowingMode(any(), anyInt()); } } @Test public void testSetAdjacentTaskFragments() { final TaskFragmentContainer container0 = mController.newContainer(mActivity, TASK_ID); final TaskFragmentContainer container1 = mController.newContainer(mActivity, TASK_ID); mPresenter.setAdjacentTaskFragments(mTransaction, container0.getTaskFragmentToken(), container1.getTaskFragmentToken(), null /* adjacentParams */); verify(mTransaction).setAdjacentTaskFragments(container0.getTaskFragmentToken(), container1.getTaskFragmentToken(), null /* adjacentParams */); // No request to set the same adjacent TaskFragments. clearInvocations(mTransaction); mPresenter.setAdjacentTaskFragments(mTransaction, container0.getTaskFragmentToken(), container1.getTaskFragmentToken(), null /* adjacentParams */); verify(mTransaction, never()).setAdjacentTaskFragments(any(), any(), any()); } @Test public void testClearAdjacentTaskFragments() { final TaskFragmentContainer container0 = mController.newContainer(mActivity, TASK_ID); final TaskFragmentContainer container1 = mController.newContainer(mActivity, TASK_ID); // No request to clear as it is not set by default. mPresenter.clearAdjacentTaskFragments(mTransaction, container0.getTaskFragmentToken()); verify(mTransaction, never()).clearAdjacentTaskFragments(any()); mPresenter.setAdjacentTaskFragments(mTransaction, container0.getTaskFragmentToken(), container1.getTaskFragmentToken(), null /* adjacentParams */); mPresenter.clearAdjacentTaskFragments(mTransaction, container0.getTaskFragmentToken()); verify(mTransaction).clearAdjacentTaskFragments(container0.getTaskFragmentToken()); // No request to clear on either of the previous cleared TasKFragments. clearInvocations(mTransaction); mPresenter.clearAdjacentTaskFragments(mTransaction, container0.getTaskFragmentToken()); mPresenter.clearAdjacentTaskFragments(mTransaction, container1.getTaskFragmentToken()); verify(mTransaction, never()).clearAdjacentTaskFragments(any()); } @Test public void testSetCompanionTaskFragment() { final TaskFragmentContainer container0 = mController.newContainer(mActivity, TASK_ID); final TaskFragmentContainer container1 = mController.newContainer(mActivity, TASK_ID); mPresenter.setCompanionTaskFragment(mTransaction, container0.getTaskFragmentToken(), container1.getTaskFragmentToken()); verify(mTransaction).setCompanionTaskFragment(container0.getTaskFragmentToken(), container1.getTaskFragmentToken()); // No request to set the same adjacent TaskFragments. clearInvocations(mTransaction); mPresenter.setCompanionTaskFragment(mTransaction, container0.getTaskFragmentToken(), container1.getTaskFragmentToken()); verify(mTransaction, never()).setCompanionTaskFragment(any(), any()); } @Test @Test public void testUpdateAnimationParams() { public void testUpdateAnimationParams() { final TaskFragmentContainer container = mController.newContainer(mActivity, TASK_ID); final TaskFragmentContainer container = mController.newContainer(mActivity, TASK_ID); Loading Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java +29 −13 Original line number Original line Diff line number Diff line Loading @@ -154,7 +154,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { activityOptions); activityOptions); // Set adjacent to each other so that the containers below will be invisible. // Set adjacent to each other so that the containers below will be invisible. setAdjacentTaskFragments(wct, launchingFragmentToken, secondaryFragmentToken, rule); setAdjacentTaskFragmentsWithRule(wct, launchingFragmentToken, secondaryFragmentToken, rule); setCompanionTaskFragment(wct, launchingFragmentToken, secondaryFragmentToken, rule, setCompanionTaskFragment(wct, launchingFragmentToken, secondaryFragmentToken, rule, false /* isStacked */); false /* isStacked */); } } Loading @@ -167,7 +167,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { void expandTaskFragment(@NonNull WindowContainerTransaction wct, void expandTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken) { @NonNull IBinder fragmentToken) { resizeTaskFragment(wct, fragmentToken, new Rect()); resizeTaskFragment(wct, fragmentToken, new Rect()); setAdjacentTaskFragments(wct, fragmentToken, null /* secondary */, null /* splitRule */); clearAdjacentTaskFragments(wct, fragmentToken); updateWindowingMode(wct, fragmentToken, WINDOWING_MODE_UNDEFINED); updateWindowingMode(wct, fragmentToken, WINDOWING_MODE_UNDEFINED); updateAnimationParams(wct, fragmentToken, TaskFragmentAnimationParams.DEFAULT); updateAnimationParams(wct, fragmentToken, TaskFragmentAnimationParams.DEFAULT); } } Loading Loading @@ -238,26 +238,37 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { wct.reparentActivityToTaskFragment(fragmentToken, reparentActivityToken); wct.reparentActivityToTaskFragment(fragmentToken, reparentActivityToken); } } void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct, /** @NonNull IBinder primary, @Nullable IBinder secondary, @Nullable SplitRule splitRule) { * Sets the two given TaskFragments as adjacent to each other with respecting the given if (secondary == null) { * {@link SplitRule} for {@link WindowContainerTransaction.TaskFragmentAdjacentParams}. wct.clearAdjacentTaskFragments(primary); */ return; void setAdjacentTaskFragmentsWithRule(@NonNull WindowContainerTransaction wct, } @NonNull IBinder primary, @NonNull IBinder secondary, @NonNull SplitRule splitRule) { WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams = null; WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams = null; final boolean finishSecondaryWithPrimary = final boolean finishSecondaryWithPrimary = splitRule != null && SplitContainer.shouldFinishSecondaryWithPrimary(splitRule); SplitContainer.shouldFinishSecondaryWithPrimary(splitRule); final boolean finishPrimaryWithSecondary = final boolean finishPrimaryWithSecondary = splitRule != null && SplitContainer.shouldFinishPrimaryWithSecondary(splitRule); SplitContainer.shouldFinishPrimaryWithSecondary(splitRule); if (finishSecondaryWithPrimary || finishPrimaryWithSecondary) { if (finishSecondaryWithPrimary || finishPrimaryWithSecondary) { adjacentParams = new WindowContainerTransaction.TaskFragmentAdjacentParams(); adjacentParams = new WindowContainerTransaction.TaskFragmentAdjacentParams(); adjacentParams.setShouldDelayPrimaryLastActivityRemoval(finishSecondaryWithPrimary); adjacentParams.setShouldDelayPrimaryLastActivityRemoval(finishSecondaryWithPrimary); adjacentParams.setShouldDelaySecondaryLastActivityRemoval(finishPrimaryWithSecondary); adjacentParams.setShouldDelaySecondaryLastActivityRemoval(finishPrimaryWithSecondary); } } setAdjacentTaskFragments(wct, primary, secondary, adjacentParams); } void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @NonNull IBinder secondary, @Nullable WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams) { wct.setAdjacentTaskFragments(primary, secondary, adjacentParams); wct.setAdjacentTaskFragments(primary, secondary, adjacentParams); } } void clearAdjacentTaskFragments(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken) { // Clear primary will also clear secondary. wct.clearAdjacentTaskFragments(fragmentToken); } void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct, void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @NonNull IBinder secondary, @NonNull SplitRule splitRule, @NonNull IBinder primary, @NonNull IBinder secondary, @NonNull SplitRule splitRule, boolean isStacked) { boolean isStacked) { Loading @@ -268,7 +279,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { } else { } else { finishPrimaryWithSecondary = shouldFinishPrimaryWithSecondary(splitRule); finishPrimaryWithSecondary = shouldFinishPrimaryWithSecondary(splitRule); } } wct.setCompanionTaskFragment(primary, finishPrimaryWithSecondary ? secondary : null); setCompanionTaskFragment(wct, primary, finishPrimaryWithSecondary ? secondary : null); final boolean finishSecondaryWithPrimary; final boolean finishSecondaryWithPrimary; if (isStacked) { if (isStacked) { Loading @@ -277,7 +288,12 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { } else { } else { finishSecondaryWithPrimary = shouldFinishSecondaryWithPrimary(splitRule); finishSecondaryWithPrimary = shouldFinishSecondaryWithPrimary(splitRule); } } wct.setCompanionTaskFragment(secondary, finishSecondaryWithPrimary ? primary : null); setCompanionTaskFragment(wct, secondary, finishSecondaryWithPrimary ? primary : null); } void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @Nullable IBinder secondary) { wct.setCompanionTaskFragment(primary, secondary); } } void resizeTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken, void resizeTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken, Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +3 −0 Original line number Original line Diff line number Diff line Loading @@ -525,6 +525,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // All overrides will be cleanup. // All overrides will be cleanup. container.setLastRequestedBounds(null /* bounds */); container.setLastRequestedBounds(null /* bounds */); container.setLastRequestedWindowingMode(WINDOWING_MODE_UNDEFINED); container.setLastRequestedWindowingMode(WINDOWING_MODE_UNDEFINED); container.clearLastAdjacentTaskFragment(); container.setLastCompanionTaskFragment(null /* fragmentToken */); container.setLastRequestAnimationParams(TaskFragmentAnimationParams.DEFAULT); cleanupForEnterPip(wct, container); cleanupForEnterPip(wct, container); } else if (wasInPip) { } else if (wasInPip) { // Exit PIP. // Exit PIP. Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +64 −7 Original line number Original line Diff line number Diff line Loading @@ -385,10 +385,9 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { // secondaryContainer could not be finished. // secondaryContainer could not be finished. boolean isStacked = !shouldShowSplit(splitAttributes); boolean isStacked = !shouldShowSplit(splitAttributes); if (isStacked) { if (isStacked) { setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(), clearAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken()); null /* secondary */, null /* splitRule */); } else { } else { setAdjacentTaskFragments(wct, primaryContainer.getTaskFragmentToken(), setAdjacentTaskFragmentsWithRule(wct, primaryContainer.getTaskFragmentToken(), secondaryContainer.getTaskFragmentToken(), splitRule); secondaryContainer.getTaskFragmentToken(), splitRule); } } setCompanionTaskFragment(wct, primaryContainer.getTaskFragmentToken(), setCompanionTaskFragment(wct, primaryContainer.getTaskFragmentToken(), Loading Loading @@ -425,7 +424,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { fragmentOptions.getFragmentToken()); fragmentOptions.getFragmentToken()); if (container == null) { if (container == null) { throw new IllegalStateException( throw new IllegalStateException( "Creating a task fragment that is not registered with controller."); "Creating a TaskFragment that is not registered with controller."); } } container.setLastRequestedBounds(fragmentOptions.getInitialRelativeBounds()); container.setLastRequestedBounds(fragmentOptions.getInitialRelativeBounds()); Loading @@ -439,7 +438,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { TaskFragmentContainer container = mController.getContainer(fragmentToken); TaskFragmentContainer container = mController.getContainer(fragmentToken); if (container == null) { if (container == null) { throw new IllegalStateException( throw new IllegalStateException( "Resizing a task fragment that is not registered with controller."); "Resizing a TaskFragment that is not registered with controller."); } } if (container.areLastRequestedBoundsEqual(relBounds)) { if (container.areLastRequestedBoundsEqual(relBounds)) { Loading @@ -456,7 +455,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @NonNull IBinder fragmentToken, @WindowingMode int windowingMode) { @NonNull IBinder fragmentToken, @WindowingMode int windowingMode) { final TaskFragmentContainer container = mController.getContainer(fragmentToken); final TaskFragmentContainer container = mController.getContainer(fragmentToken); if (container == null) { if (container == null) { throw new IllegalStateException("Setting windowing mode for a task fragment that is" throw new IllegalStateException("Setting windowing mode for a TaskFragment that is" + " not registered with controller."); + " not registered with controller."); } } Loading @@ -474,7 +473,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @NonNull IBinder fragmentToken, @NonNull TaskFragmentAnimationParams animationParams) { @NonNull IBinder fragmentToken, @NonNull TaskFragmentAnimationParams animationParams) { final TaskFragmentContainer container = mController.getContainer(fragmentToken); final TaskFragmentContainer container = mController.getContainer(fragmentToken); if (container == null) { if (container == null) { throw new IllegalStateException("Setting animation params for a task fragment that is" throw new IllegalStateException("Setting animation params for a TaskFragment that is" + " not registered with controller."); + " not registered with controller."); } } Loading @@ -487,6 +486,64 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { super.updateAnimationParams(wct, fragmentToken, animationParams); super.updateAnimationParams(wct, fragmentToken, animationParams); } } @Override void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @NonNull IBinder secondary, @Nullable WindowContainerTransaction.TaskFragmentAdjacentParams adjacentParams) { final TaskFragmentContainer primaryContainer = mController.getContainer(primary); final TaskFragmentContainer secondaryContainer = mController.getContainer(secondary); if (primaryContainer == null || secondaryContainer == null) { throw new IllegalStateException("setAdjacentTaskFragments on TaskFragment that is" + " not registered with controller."); } if (primaryContainer.isLastAdjacentTaskFragmentEqual(secondary, adjacentParams) && secondaryContainer.isLastAdjacentTaskFragmentEqual(primary, adjacentParams)) { // Return early if the same adjacent TaskFragments were already requested return; } primaryContainer.setLastAdjacentTaskFragment(secondary, adjacentParams); secondaryContainer.setLastAdjacentTaskFragment(primary, adjacentParams); super.setAdjacentTaskFragments(wct, primary, secondary, adjacentParams); } @Override void clearAdjacentTaskFragments(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken) { final TaskFragmentContainer container = mController.getContainer(fragmentToken); if (container == null) { throw new IllegalStateException("clearAdjacentTaskFragments on TaskFragment that is" + " not registered with controller."); } if (container.isLastAdjacentTaskFragmentEqual(null /* fragmentToken*/, null /* params */)) { // Return early if no adjacent TaskFragment was yet requested return; } container.clearLastAdjacentTaskFragment(); super.clearAdjacentTaskFragments(wct, fragmentToken); } @Override void setCompanionTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder primary, @Nullable IBinder secondary) { final TaskFragmentContainer container = mController.getContainer(primary); if (container == null) { throw new IllegalStateException("setCompanionTaskFragment on TaskFragment that is" + " not registered with controller."); } if (container.isLastCompanionTaskFragmentEqual(secondary)) { // Return early if the same companion TaskFragment was already requested return; } container.setLastCompanionTaskFragment(secondary); super.setCompanionTaskFragment(wct, primary, secondary); } /** /** * Expands the split container if the current split bounds are smaller than the Activity or * Expands the split container if the current split bounds are smaller than the Activity or * Intent that is added to the container. * Intent that is added to the container. Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +82 −5 Original line number Original line Diff line number Diff line Loading @@ -40,6 +40,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Collections; import java.util.Iterator; import java.util.Iterator; import java.util.List; import java.util.List; import java.util.Objects; /** /** * Client-side container for a stack of activities. Corresponds to an instance of TaskFragment * Client-side container for a stack of activities. Corresponds to an instance of TaskFragment Loading Loading @@ -116,6 +117,27 @@ class TaskFragmentContainer { @NonNull @NonNull private TaskFragmentAnimationParams mLastAnimationParams = TaskFragmentAnimationParams.DEFAULT; private TaskFragmentAnimationParams mLastAnimationParams = TaskFragmentAnimationParams.DEFAULT; /** * TaskFragment token that was requested last via * {@link android.window.TaskFragmentOperation#OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS}. */ @Nullable private IBinder mLastAdjacentTaskFragment; /** * {@link WindowContainerTransaction.TaskFragmentAdjacentParams} token that was requested last * via {@link android.window.TaskFragmentOperation#OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS}. */ @Nullable private WindowContainerTransaction.TaskFragmentAdjacentParams mLastAdjacentParams; /** * TaskFragment token that was requested last via * {@link android.window.TaskFragmentOperation#OP_TYPE_SET_COMPANION_TASK_FRAGMENT}. */ @Nullable private IBinder mLastCompanionTaskFragment; /** /** * When the TaskFragment has appeared in server, but is empty, we should remove the TaskFragment * When the TaskFragment has appeared in server, but is empty, we should remove the TaskFragment * if it is still empty after the timeout. * if it is still empty after the timeout. Loading Loading @@ -591,6 +613,7 @@ class TaskFragmentContainer { /** /** * Checks if last requested bounds are equal to the provided value. * Checks if last requested bounds are equal to the provided value. * The requested bounds are relative bounds in parent coordinate. * The requested bounds are relative bounds in parent coordinate. * @see WindowContainerTransaction#setRelativeBounds */ */ boolean areLastRequestedBoundsEqual(@Nullable Rect relBounds) { boolean areLastRequestedBoundsEqual(@Nullable Rect relBounds) { return (relBounds == null && mLastRequestedBounds.isEmpty()) return (relBounds == null && mLastRequestedBounds.isEmpty()) Loading @@ -600,6 +623,7 @@ class TaskFragmentContainer { /** /** * Updates the last requested bounds. * Updates the last requested bounds. * The requested bounds are relative bounds in parent coordinate. * The requested bounds are relative bounds in parent coordinate. * @see WindowContainerTransaction#setRelativeBounds */ */ void setLastRequestedBounds(@Nullable Rect relBounds) { void setLastRequestedBounds(@Nullable Rect relBounds) { if (relBounds == null) { if (relBounds == null) { Loading @@ -609,13 +633,9 @@ class TaskFragmentContainer { } } } } @NonNull Rect getLastRequestedBounds() { return mLastRequestedBounds; } /** /** * Checks if last requested windowing mode is equal to the provided value. * Checks if last requested windowing mode is equal to the provided value. * @see WindowContainerTransaction#setWindowingMode */ */ boolean isLastRequestedWindowingModeEqual(@WindowingMode int windowingMode) { boolean isLastRequestedWindowingModeEqual(@WindowingMode int windowingMode) { return mLastRequestedWindowingMode == windowingMode; return mLastRequestedWindowingMode == windowingMode; Loading @@ -623,6 +643,7 @@ class TaskFragmentContainer { /** /** * Updates the last requested windowing mode. * Updates the last requested windowing mode. * @see WindowContainerTransaction#setWindowingMode */ */ void setLastRequestedWindowingMode(@WindowingMode int windowingModes) { void setLastRequestedWindowingMode(@WindowingMode int windowingModes) { mLastRequestedWindowingMode = windowingModes; mLastRequestedWindowingMode = windowingModes; Loading @@ -630,6 +651,7 @@ class TaskFragmentContainer { /** /** * Checks if last requested {@link TaskFragmentAnimationParams} are equal to the provided value. * Checks if last requested {@link TaskFragmentAnimationParams} are equal to the provided value. * @see android.window.TaskFragmentOperation#OP_TYPE_SET_ANIMATION_PARAMS */ */ boolean areLastRequestedAnimationParamsEqual( boolean areLastRequestedAnimationParamsEqual( @NonNull TaskFragmentAnimationParams animationParams) { @NonNull TaskFragmentAnimationParams animationParams) { Loading @@ -638,11 +660,66 @@ class TaskFragmentContainer { /** /** * Updates the last requested {@link TaskFragmentAnimationParams}. * Updates the last requested {@link TaskFragmentAnimationParams}. * @see android.window.TaskFragmentOperation#OP_TYPE_SET_ANIMATION_PARAMS */ */ void setLastRequestAnimationParams(@NonNull TaskFragmentAnimationParams animationParams) { void setLastRequestAnimationParams(@NonNull TaskFragmentAnimationParams animationParams) { mLastAnimationParams = animationParams; mLastAnimationParams = animationParams; } } /** * Checks if last requested adjacent TaskFragment token and params are equal to the provided * values. * @see android.window.TaskFragmentOperation#OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS * @see android.window.TaskFragmentOperation#OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS */ boolean isLastAdjacentTaskFragmentEqual(@Nullable IBinder fragmentToken, @Nullable WindowContainerTransaction.TaskFragmentAdjacentParams params) { return Objects.equals(mLastAdjacentTaskFragment, fragmentToken) && Objects.equals(mLastAdjacentParams, params); } /** * Updates the last requested adjacent TaskFragment token and params. * @see android.window.TaskFragmentOperation#OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS */ void setLastAdjacentTaskFragment(@NonNull IBinder fragmentToken, @NonNull WindowContainerTransaction.TaskFragmentAdjacentParams params) { mLastAdjacentTaskFragment = fragmentToken; mLastAdjacentParams = params; } /** * Clears the last requested adjacent TaskFragment token and params. * @see android.window.TaskFragmentOperation#OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS */ void clearLastAdjacentTaskFragment() { final TaskFragmentContainer lastAdjacentTaskFragment = mLastAdjacentTaskFragment != null ? mController.getContainer(mLastAdjacentTaskFragment) : null; mLastAdjacentTaskFragment = null; mLastAdjacentParams = null; if (lastAdjacentTaskFragment != null) { // Clear the previous adjacent TaskFragment as well. lastAdjacentTaskFragment.clearLastAdjacentTaskFragment(); } } /** * Checks if last requested companion TaskFragment token is equal to the provided value. * @see android.window.TaskFragmentOperation#OP_TYPE_SET_COMPANION_TASK_FRAGMENT */ boolean isLastCompanionTaskFragmentEqual(@Nullable IBinder fragmentToken) { return Objects.equals(mLastCompanionTaskFragment, fragmentToken); } /** * Updates the last requested companion TaskFragment token. * @see android.window.TaskFragmentOperation#OP_TYPE_SET_COMPANION_TASK_FRAGMENT */ void setLastCompanionTaskFragment(@Nullable IBinder fragmentToken) { mLastCompanionTaskFragment = fragmentToken; } /** Gets the parent leaf Task id. */ /** Gets the parent leaf Task id. */ int getTaskId() { int getTaskId() { return mTaskContainer.getTaskId(); return mTaskContainer.getTaskId(); Loading
libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java +58 −0 Original line number Original line Diff line number Diff line Loading @@ -176,6 +176,64 @@ public class SplitPresenterTest { verify(mTransaction, never()).setWindowingMode(any(), anyInt()); verify(mTransaction, never()).setWindowingMode(any(), anyInt()); } } @Test public void testSetAdjacentTaskFragments() { final TaskFragmentContainer container0 = mController.newContainer(mActivity, TASK_ID); final TaskFragmentContainer container1 = mController.newContainer(mActivity, TASK_ID); mPresenter.setAdjacentTaskFragments(mTransaction, container0.getTaskFragmentToken(), container1.getTaskFragmentToken(), null /* adjacentParams */); verify(mTransaction).setAdjacentTaskFragments(container0.getTaskFragmentToken(), container1.getTaskFragmentToken(), null /* adjacentParams */); // No request to set the same adjacent TaskFragments. clearInvocations(mTransaction); mPresenter.setAdjacentTaskFragments(mTransaction, container0.getTaskFragmentToken(), container1.getTaskFragmentToken(), null /* adjacentParams */); verify(mTransaction, never()).setAdjacentTaskFragments(any(), any(), any()); } @Test public void testClearAdjacentTaskFragments() { final TaskFragmentContainer container0 = mController.newContainer(mActivity, TASK_ID); final TaskFragmentContainer container1 = mController.newContainer(mActivity, TASK_ID); // No request to clear as it is not set by default. mPresenter.clearAdjacentTaskFragments(mTransaction, container0.getTaskFragmentToken()); verify(mTransaction, never()).clearAdjacentTaskFragments(any()); mPresenter.setAdjacentTaskFragments(mTransaction, container0.getTaskFragmentToken(), container1.getTaskFragmentToken(), null /* adjacentParams */); mPresenter.clearAdjacentTaskFragments(mTransaction, container0.getTaskFragmentToken()); verify(mTransaction).clearAdjacentTaskFragments(container0.getTaskFragmentToken()); // No request to clear on either of the previous cleared TasKFragments. clearInvocations(mTransaction); mPresenter.clearAdjacentTaskFragments(mTransaction, container0.getTaskFragmentToken()); mPresenter.clearAdjacentTaskFragments(mTransaction, container1.getTaskFragmentToken()); verify(mTransaction, never()).clearAdjacentTaskFragments(any()); } @Test public void testSetCompanionTaskFragment() { final TaskFragmentContainer container0 = mController.newContainer(mActivity, TASK_ID); final TaskFragmentContainer container1 = mController.newContainer(mActivity, TASK_ID); mPresenter.setCompanionTaskFragment(mTransaction, container0.getTaskFragmentToken(), container1.getTaskFragmentToken()); verify(mTransaction).setCompanionTaskFragment(container0.getTaskFragmentToken(), container1.getTaskFragmentToken()); // No request to set the same adjacent TaskFragments. clearInvocations(mTransaction); mPresenter.setCompanionTaskFragment(mTransaction, container0.getTaskFragmentToken(), container1.getTaskFragmentToken()); verify(mTransaction, never()).setCompanionTaskFragment(any(), any()); } @Test @Test public void testUpdateAnimationParams() { public void testUpdateAnimationParams() { final TaskFragmentContainer container = mController.newContainer(mActivity, TASK_ID); final TaskFragmentContainer container = mController.newContainer(mActivity, TASK_ID); Loading