Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +7 −7 Original line number Diff line number Diff line Loading @@ -621,14 +621,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId()) .mSplitContainers; if (splitContainers == null || splitContainer != splitContainers.get(splitContainers.size() - 1)) { if (splitContainer != splitContainers.get(splitContainers.size() - 1)) { // Skip position update - it isn't the topmost split. return; } if (splitContainer.getPrimaryContainer().isEmpty() || splitContainer.getSecondaryContainer().isEmpty()) { // Skip position update - one or both containers are empty. if (splitContainer.getPrimaryContainer().isFinished() || splitContainer.getSecondaryContainer().isFinished()) { // Skip position update - one or both containers are finished. return; } if (dismissPlaceholderIfNecessary(splitContainer)) { Loading @@ -645,7 +644,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen private SplitContainer getActiveSplitForContainer(@NonNull TaskFragmentContainer container) { final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId()) .mSplitContainers; if (splitContainers == null) { if (splitContainers.isEmpty()) { return null; } for (int i = splitContainers.size() - 1; i >= 0; i--) { Loading Loading @@ -723,7 +722,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return true; } private boolean dismissPlaceholderIfNecessary(@NonNull SplitContainer splitContainer) { @VisibleForTesting boolean dismissPlaceholderIfNecessary(@NonNull SplitContainer splitContainer) { if (!splitContainer.isPlaceholderContainer()) { return false; } Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java +2 −0 Original line number Diff line number Diff line Loading @@ -47,9 +47,11 @@ class TaskContainer { private int mWindowingMode = WINDOWING_MODE_UNDEFINED; /** Active TaskFragments in this Task. */ @NonNull final List<TaskFragmentContainer> mContainers = new ArrayList<>(); /** Active split pairs in this Task. */ @NonNull final List<SplitContainer> mSplitContainers = new ArrayList<>(); /** Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +4 −3 Original line number Diff line number Diff line Loading @@ -341,14 +341,15 @@ class TaskFragmentContainer { private String toString(boolean includeContainersToFinishOnExit) { return "TaskFragmentContainer{" + " token=" + mToken + " info=" + mInfo + " topNonFinishingActivity=" + getTopNonFinishingActivity() + " runningActivityCount=" + getRunningActivityCount() + " isFinished=" + mIsFinished + " lastRequestedBounds=" + mLastRequestedBounds + " pendingAppearedActivities=" + mPendingAppearedActivities + (includeContainersToFinishOnExit ? " containersToFinishOnExit=" + containersToFinishOnExitToString() : "") + " activitiesToFinishOnExit=" + mActivitiesToFinishOnExit + " isFinished=" + mIsFinished + " lastRequestedBounds=" + mLastRequestedBounds + " info=" + mInfo + "}"; } Loading libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java +78 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; Loading @@ -35,6 +37,7 @@ import android.content.res.Resources; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.window.TaskFragmentInfo; import android.window.WindowContainerTransaction; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; Loading @@ -45,6 +48,8 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.List; /** * Test class for {@link SplitController}. * Loading @@ -64,6 +69,8 @@ public class SplitControllerTest { private Resources mActivityResources; @Mock private TaskFragmentInfo mInfo; @Mock private WindowContainerTransaction mTransaction; private SplitController mSplitController; private SplitPresenter mSplitPresenter; Loading Loading @@ -140,4 +147,75 @@ public class SplitControllerTest { assertNotNull(taskContainer); assertEquals(TASK_BOUNDS, taskContainer.getTaskBounds()); } @Test public void testUpdateContainer() { // Make SplitController#launchPlaceholderIfNecessary(TaskFragmentContainer) return true // and verify if shouldContainerBeExpanded() not called. final TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID); spyOn(tf); doReturn(mActivity).when(tf).getTopNonFinishingActivity(); doReturn(true).when(tf).isEmpty(); doReturn(true).when(mSplitController).launchPlaceholderIfNecessary(mActivity); doNothing().when(mSplitPresenter).updateSplitContainer(any(), any(), any()); mSplitController.updateContainer(mTransaction, tf); verify(mSplitController, never()).shouldContainerBeExpanded(any()); // Verify if tf should be expanded, getTopActiveContainer() won't be called doReturn(null).when(tf).getTopNonFinishingActivity(); doReturn(true).when(mSplitController).shouldContainerBeExpanded(tf); mSplitController.updateContainer(mTransaction, tf); verify(mSplitController, never()).getTopActiveContainer(TASK_ID); // Verify if tf is not in split, dismissPlaceholderIfNecessary won't be called. doReturn(false).when(mSplitController).shouldContainerBeExpanded(tf); mSplitController.updateContainer(mTransaction, tf); verify(mSplitController, never()).dismissPlaceholderIfNecessary(any()); // Verify if tf is not in the top splitContainer, final SplitContainer splitContainer = mock(SplitContainer.class); doReturn(tf).when(splitContainer).getPrimaryContainer(); doReturn(tf).when(splitContainer).getSecondaryContainer(); final List<SplitContainer> splitContainers = mSplitController.getTaskContainer(TASK_ID).mSplitContainers; splitContainers.add(splitContainer); // Add a mock SplitContainer on top of splitContainer splitContainers.add(1, mock(SplitContainer.class)); mSplitController.updateContainer(mTransaction, tf); verify(mSplitController, never()).dismissPlaceholderIfNecessary(any()); // Verify if one or both containers in the top SplitContainer are finished, // dismissPlaceholder() won't be called. splitContainers.remove(1); doReturn(true).when(tf).isFinished(); mSplitController.updateContainer(mTransaction, tf); verify(mSplitController, never()).dismissPlaceholderIfNecessary(any()); // Verify if placeholder should be dismissed, updateSplitContainer() won't be called. doReturn(false).when(tf).isFinished(); doReturn(true).when(mSplitController) .dismissPlaceholderIfNecessary(splitContainer); mSplitController.updateContainer(mTransaction, tf); verify(mSplitPresenter, never()).updateSplitContainer(any(), any(), any()); // Verify if the top active split is updated if both of its containers are not finished. doReturn(false).when(mSplitController) .dismissPlaceholderIfNecessary(splitContainer); mSplitController.updateContainer(mTransaction, tf); verify(mSplitPresenter).updateSplitContainer(eq(splitContainer), eq(tf), eq(mTransaction)); } } Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +7 −7 Original line number Diff line number Diff line Loading @@ -621,14 +621,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId()) .mSplitContainers; if (splitContainers == null || splitContainer != splitContainers.get(splitContainers.size() - 1)) { if (splitContainer != splitContainers.get(splitContainers.size() - 1)) { // Skip position update - it isn't the topmost split. return; } if (splitContainer.getPrimaryContainer().isEmpty() || splitContainer.getSecondaryContainer().isEmpty()) { // Skip position update - one or both containers are empty. if (splitContainer.getPrimaryContainer().isFinished() || splitContainer.getSecondaryContainer().isFinished()) { // Skip position update - one or both containers are finished. return; } if (dismissPlaceholderIfNecessary(splitContainer)) { Loading @@ -645,7 +644,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen private SplitContainer getActiveSplitForContainer(@NonNull TaskFragmentContainer container) { final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId()) .mSplitContainers; if (splitContainers == null) { if (splitContainers.isEmpty()) { return null; } for (int i = splitContainers.size() - 1; i >= 0; i--) { Loading Loading @@ -723,7 +722,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return true; } private boolean dismissPlaceholderIfNecessary(@NonNull SplitContainer splitContainer) { @VisibleForTesting boolean dismissPlaceholderIfNecessary(@NonNull SplitContainer splitContainer) { if (!splitContainer.isPlaceholderContainer()) { return false; } Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java +2 −0 Original line number Diff line number Diff line Loading @@ -47,9 +47,11 @@ class TaskContainer { private int mWindowingMode = WINDOWING_MODE_UNDEFINED; /** Active TaskFragments in this Task. */ @NonNull final List<TaskFragmentContainer> mContainers = new ArrayList<>(); /** Active split pairs in this Task. */ @NonNull final List<SplitContainer> mSplitContainers = new ArrayList<>(); /** Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +4 −3 Original line number Diff line number Diff line Loading @@ -341,14 +341,15 @@ class TaskFragmentContainer { private String toString(boolean includeContainersToFinishOnExit) { return "TaskFragmentContainer{" + " token=" + mToken + " info=" + mInfo + " topNonFinishingActivity=" + getTopNonFinishingActivity() + " runningActivityCount=" + getRunningActivityCount() + " isFinished=" + mIsFinished + " lastRequestedBounds=" + mLastRequestedBounds + " pendingAppearedActivities=" + mPendingAppearedActivities + (includeContainersToFinishOnExit ? " containersToFinishOnExit=" + containersToFinishOnExitToString() : "") + " activitiesToFinishOnExit=" + mActivitiesToFinishOnExit + " isFinished=" + mIsFinished + " lastRequestedBounds=" + mLastRequestedBounds + " info=" + mInfo + "}"; } Loading
libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java +78 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; Loading @@ -35,6 +37,7 @@ import android.content.res.Resources; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.window.TaskFragmentInfo; import android.window.WindowContainerTransaction; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; Loading @@ -45,6 +48,8 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.List; /** * Test class for {@link SplitController}. * Loading @@ -64,6 +69,8 @@ public class SplitControllerTest { private Resources mActivityResources; @Mock private TaskFragmentInfo mInfo; @Mock private WindowContainerTransaction mTransaction; private SplitController mSplitController; private SplitPresenter mSplitPresenter; Loading Loading @@ -140,4 +147,75 @@ public class SplitControllerTest { assertNotNull(taskContainer); assertEquals(TASK_BOUNDS, taskContainer.getTaskBounds()); } @Test public void testUpdateContainer() { // Make SplitController#launchPlaceholderIfNecessary(TaskFragmentContainer) return true // and verify if shouldContainerBeExpanded() not called. final TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID); spyOn(tf); doReturn(mActivity).when(tf).getTopNonFinishingActivity(); doReturn(true).when(tf).isEmpty(); doReturn(true).when(mSplitController).launchPlaceholderIfNecessary(mActivity); doNothing().when(mSplitPresenter).updateSplitContainer(any(), any(), any()); mSplitController.updateContainer(mTransaction, tf); verify(mSplitController, never()).shouldContainerBeExpanded(any()); // Verify if tf should be expanded, getTopActiveContainer() won't be called doReturn(null).when(tf).getTopNonFinishingActivity(); doReturn(true).when(mSplitController).shouldContainerBeExpanded(tf); mSplitController.updateContainer(mTransaction, tf); verify(mSplitController, never()).getTopActiveContainer(TASK_ID); // Verify if tf is not in split, dismissPlaceholderIfNecessary won't be called. doReturn(false).when(mSplitController).shouldContainerBeExpanded(tf); mSplitController.updateContainer(mTransaction, tf); verify(mSplitController, never()).dismissPlaceholderIfNecessary(any()); // Verify if tf is not in the top splitContainer, final SplitContainer splitContainer = mock(SplitContainer.class); doReturn(tf).when(splitContainer).getPrimaryContainer(); doReturn(tf).when(splitContainer).getSecondaryContainer(); final List<SplitContainer> splitContainers = mSplitController.getTaskContainer(TASK_ID).mSplitContainers; splitContainers.add(splitContainer); // Add a mock SplitContainer on top of splitContainer splitContainers.add(1, mock(SplitContainer.class)); mSplitController.updateContainer(mTransaction, tf); verify(mSplitController, never()).dismissPlaceholderIfNecessary(any()); // Verify if one or both containers in the top SplitContainer are finished, // dismissPlaceholder() won't be called. splitContainers.remove(1); doReturn(true).when(tf).isFinished(); mSplitController.updateContainer(mTransaction, tf); verify(mSplitController, never()).dismissPlaceholderIfNecessary(any()); // Verify if placeholder should be dismissed, updateSplitContainer() won't be called. doReturn(false).when(tf).isFinished(); doReturn(true).when(mSplitController) .dismissPlaceholderIfNecessary(splitContainer); mSplitController.updateContainer(mTransaction, tf); verify(mSplitPresenter, never()).updateSplitContainer(any(), any(), any()); // Verify if the top active split is updated if both of its containers are not finished. doReturn(false).when(mSplitController) .dismissPlaceholderIfNecessary(splitContainer); mSplitController.updateContainer(mTransaction, tf); verify(mSplitPresenter).updateSplitContainer(eq(splitContainer), eq(tf), eq(mTransaction)); } }