Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +43 −23 Original line number Diff line number Diff line Loading @@ -241,7 +241,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // launching to top. We allow split as primary for activity reparent because the // activity may be split as primary before it is reparented out. In that case, we want // to show it as primary again when it is reparented back. if (!resolveActivityToContainer(activity, true /* canSplitAsPrimary */)) { if (!resolveActivityToContainer(activity, true /* isOnReparent */)) { // When there is no embedding rule matched, try to place it in the top container // like a normal launch. placeActivityInTopContainer(activity); Loading Loading @@ -353,21 +353,21 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen void onActivityCreated(@NonNull Activity launchedActivity) { // TODO(b/229680885): we don't support launching into primary yet because we want to always // launch the new activity on top. resolveActivityToContainer(launchedActivity, false /* canSplitAsPrimary */); resolveActivityToContainer(launchedActivity, false /* isOnReparent */); updateCallbackIfNecessary(); } /** * Checks if the new added activity should be routed to a particular container. It can create a * new container for the activity and a new split container if necessary. * @param launchedActivity the new launched activity. * @param canSplitAsPrimary whether we can put the new launched activity into primary split. * @param activity the activity that is newly added to the Task. * @param isOnReparent whether the activity is reparented to the Task instead of new launched. * We only support to split as primary for reparented activity for now. * @return {@code true} if the activity was placed in TaskFragment container. */ @VisibleForTesting boolean resolveActivityToContainer(@NonNull Activity launchedActivity, boolean canSplitAsPrimary) { if (isInPictureInPicture(launchedActivity) || launchedActivity.isFinishing()) { boolean resolveActivityToContainer(@NonNull Activity activity, boolean isOnReparent) { if (isInPictureInPicture(activity) || activity.isFinishing()) { // We don't embed activity when it is in PIP, or finishing. Return true since we don't // want any extra handling. return true; Loading @@ -385,33 +385,32 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen */ // 1. Whether the new launched activity should always expand. if (shouldExpand(launchedActivity, null /* intent */)) { expandActivity(launchedActivity); if (shouldExpand(activity, null /* intent */)) { expandActivity(activity); return true; } // 2. Whether the new launched activity should launch a placeholder. if (launchPlaceholderIfNecessary(launchedActivity)) { if (launchPlaceholderIfNecessary(activity, !isOnReparent)) { return true; } // 3. Whether the new launched activity has already been in a split with a rule matched. if (isNewActivityInSplitWithRuleMatched(launchedActivity)) { if (isNewActivityInSplitWithRuleMatched(activity)) { return true; } // 4. Whether the activity below (if any) should be split with the new launched activity. final Activity activityBelow = findActivityBelow(launchedActivity); final Activity activityBelow = findActivityBelow(activity); if (activityBelow == null) { // Can't find any activity below. return false; } if (putActivitiesIntoSplitIfNecessary(activityBelow, launchedActivity)) { if (putActivitiesIntoSplitIfNecessary(activityBelow, activity)) { // Have split rule of [ activityBelow | launchedActivity ]. return true; } if (canSplitAsPrimary && putActivitiesIntoSplitIfNecessary(launchedActivity, activityBelow)) { if (isOnReparent && putActivitiesIntoSplitIfNecessary(activity, activityBelow)) { // Have split rule of [ launchedActivity | activityBelow]. return true; } Loading @@ -430,17 +429,16 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen ? topSplit.getSecondaryContainer() : topSplit.getPrimaryContainer(); final Activity otherTopActivity = otherTopContainer.getTopNonFinishingActivity(); if (otherTopActivity == null || otherTopActivity == launchedActivity) { if (otherTopActivity == null || otherTopActivity == activity) { // Can't find the top activity on the other split TaskFragment. return false; } if (putActivitiesIntoSplitIfNecessary(otherTopActivity, launchedActivity)) { if (putActivitiesIntoSplitIfNecessary(otherTopActivity, activity)) { // Have split rule of [ otherTopActivity | launchedActivity ]. return true; } // Have split rule of [ launchedActivity | otherTopActivity]. return canSplitAsPrimary && putActivitiesIntoSplitIfNecessary(launchedActivity, otherTopActivity); return isOnReparent && putActivitiesIntoSplitIfNecessary(activity, otherTopActivity); } /** Loading Loading @@ -603,7 +601,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } // Check if activity requires a placeholder launchPlaceholderIfNecessary(activity); launchPlaceholderIfNecessary(activity, false /* isOnCreated */); } @VisibleForTesting Loading Loading @@ -1043,10 +1041,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return false; } return launchPlaceholderIfNecessary(topActivity); return launchPlaceholderIfNecessary(topActivity, false /* isOnCreated */); } boolean launchPlaceholderIfNecessary(@NonNull Activity activity) { boolean launchPlaceholderIfNecessary(@NonNull Activity activity, boolean isOnCreated) { final TaskFragmentContainer container = getContainerWithActivity(activity); // Don't launch placeholder if the container is occluded. if (container != null && container != getTopActiveContainer(container.getTaskId())) { Loading @@ -1067,11 +1065,33 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } // TODO(b/190433398): Handle failed request startActivityToSide(activity, placeholderRule.getPlaceholderIntent(), null /* options */, final Bundle options = getPlaceholderOptions(activity, isOnCreated); startActivityToSide(activity, placeholderRule.getPlaceholderIntent(), options, placeholderRule, null /* failureCallback */, true /* isPlaceholder */); return true; } /** * Gets the activity options for starting the placeholder activity. In case the placeholder is * launched when the Task is in the background, we don't want to bring the Task to the front. * @param primaryActivity the primary activity to launch the placeholder from. * @param isOnCreated whether this happens during the primary activity onCreated. */ @VisibleForTesting @Nullable Bundle getPlaceholderOptions(@NonNull Activity primaryActivity, boolean isOnCreated) { // Setting avoid move to front will also skip the animation. We only want to do that when // the Task is currently in background. // Check if the primary is resumed or if this is called when the primary is onCreated // (not resumed yet). if (isOnCreated || primaryActivity.isResumed()) { return null; } final ActivityOptions options = ActivityOptions.makeBasic(); options.setAvoidMoveToFront(); return options.toBundle(); } @VisibleForTesting boolean dismissPlaceholderIfNecessary(@NonNull SplitContainer splitContainer) { if (!splitContainer.isPlaceholderContainer()) { Loading libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java +51 −29 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import static org.mockito.Mockito.never; import android.annotation.NonNull; import android.app.Activity; import android.app.ActivityOptions; import android.content.ComponentName; import android.content.Intent; import android.content.res.Configuration; Loading @@ -50,6 +51,7 @@ import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.platform.test.annotations.Presubmit; Loading Loading @@ -219,7 +221,8 @@ public class SplitControllerTest { spyOn(tf); doReturn(mActivity).when(tf).getTopNonFinishingActivity(); doReturn(true).when(tf).isEmpty(); doReturn(true).when(mSplitController).launchPlaceholderIfNecessary(mActivity); doReturn(true).when(mSplitController).launchPlaceholderIfNecessary(mActivity, false /* isOnCreated */); doNothing().when(mSplitPresenter).updateSplitContainer(any(), any(), any()); mSplitController.updateContainer(mTransaction, tf); Loading Loading @@ -287,8 +290,7 @@ public class SplitControllerTest { mSplitController.onActivityCreated(mActivity); // Disallow to split as primary because we want the new launch to be always on top. verify(mSplitController).resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); verify(mSplitController).resolveActivityToContainer(mActivity, false /* isOnReparent */); } @Test Loading @@ -297,8 +299,7 @@ public class SplitControllerTest { mActivity.getActivityToken()); // Treated as on activity created, but allow to split as primary. verify(mSplitController).resolveActivityToContainer(mActivity, true /* canSplitAsPrimary */); verify(mSplitController).resolveActivityToContainer(mActivity, true /* isOnReparent */); // Try to place the activity to the top TaskFragment when there is no matched rule. verify(mSplitController).placeActivityInTopContainer(mActivity); } Loading Loading @@ -432,7 +433,7 @@ public class SplitControllerTest { @Test public void testResolveActivityToContainer_noRuleMatched() { final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertFalse(result); verify(mSplitController, never()).newContainer(any(), any(), anyInt()); Loading @@ -444,7 +445,7 @@ public class SplitControllerTest { // When the activity is not in any TaskFragment, create a new expanded TaskFragment for it. final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); final TaskFragmentContainer container = mSplitController.getContainerWithActivity( mActivity); Loading @@ -461,7 +462,7 @@ public class SplitControllerTest { // When the activity is not in any TaskFragment, create a new expanded TaskFragment for it. final TaskFragmentContainer container = mSplitController.newContainer(mActivity, TASK_ID); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertTrue(result); verify(mSplitPresenter).expandTaskFragment(container.getTaskFragmentToken()); Loading @@ -475,7 +476,7 @@ public class SplitControllerTest { final Activity activity = createMockActivity(); addSplitTaskFragments(activity, mActivity); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); final TaskFragmentContainer container = mSplitController.getContainerWithActivity( mActivity); Loading @@ -492,11 +493,12 @@ public class SplitControllerTest { // Launch placeholder if the activity is not in any TaskFragment. final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertTrue(result); verify(mSplitPresenter).startActivityToSide(mActivity, PLACEHOLDER_INTENT, null /* activityOptions */, placeholderRule, true /* isPlaceholder */); mSplitController.getPlaceholderOptions(mActivity, true /* isOnCreated */), placeholderRule, true /* isPlaceholder */); } @Test Loading @@ -508,7 +510,7 @@ public class SplitControllerTest { mSplitController.newContainer(mActivity, TASK_ID); mSplitController.newContainer(activity, TASK_ID); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertFalse(result); verify(mSplitPresenter, never()).startActivityToSide(any(), any(), any(), any(), Loading @@ -524,11 +526,12 @@ public class SplitControllerTest { // Launch placeholder if the activity is in the topmost expanded TaskFragment. mSplitController.newContainer(mActivity, TASK_ID); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertTrue(result); verify(mSplitPresenter).startActivityToSide(mActivity, PLACEHOLDER_INTENT, null /* activityOptions */, placeholderRule, true /* isPlaceholder */); mSplitController.getPlaceholderOptions(mActivity, true /* isOnCreated */), placeholderRule, true /* isPlaceholder */); } @Test Loading @@ -539,7 +542,7 @@ public class SplitControllerTest { final Activity secondaryActivity = createMockActivity(); addSplitTaskFragments(mActivity, secondaryActivity); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertFalse(result); verify(mSplitPresenter, never()).startActivityToSide(any(), any(), any(), any(), Loading @@ -556,11 +559,12 @@ public class SplitControllerTest { final Activity primaryActivity = createMockActivity(); addSplitTaskFragments(primaryActivity, mActivity); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertTrue(result); verify(mSplitPresenter).startActivityToSide(mActivity, PLACEHOLDER_INTENT, null /* activityOptions */, placeholderRule, true /* isPlaceholder */); mSplitController.getPlaceholderOptions(mActivity, true /* isOnCreated */), placeholderRule, true /* isPlaceholder */); } @Test Loading @@ -582,7 +586,7 @@ public class SplitControllerTest { splitRule); clearInvocations(mSplitController); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertTrue(result); verify(mSplitController, never()).newContainer(any(), any(), anyInt()); Loading @@ -598,7 +602,7 @@ public class SplitControllerTest { addSplitTaskFragments(primaryActivity, mActivity); clearInvocations(mSplitController); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertTrue(result); verify(mSplitController, never()).newContainer(any(), any(), anyInt()); Loading @@ -616,7 +620,7 @@ public class SplitControllerTest { mSplitController.getContainerWithActivity(secondaryActivity) .addPendingAppearedActivity(mActivity); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertFalse(result); } Loading @@ -641,7 +645,7 @@ public class SplitControllerTest { secondaryContainer, placeholderRule); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertTrue(result); } Loading @@ -655,7 +659,7 @@ public class SplitControllerTest { TASK_ID); container.addPendingAppearedActivity(mActivity); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertTrue(result); assertSplitPair(activityBelow, mActivity); Loading @@ -671,14 +675,13 @@ public class SplitControllerTest { TASK_ID); container.addPendingAppearedActivity(mActivity); boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertFalse(result); assertEquals(container, mSplitController.getContainerWithActivity(mActivity)); // Allow to split as primary. result = mSplitController.resolveActivityToContainer(mActivity, true /* canSplitAsPrimary */); result = mSplitController.resolveActivityToContainer(mActivity, true /* isOnReparent */); assertTrue(result); assertSplitPair(mActivity, activityBelow); Loading @@ -697,7 +700,7 @@ public class SplitControllerTest { activityBelow); secondaryContainer.addPendingAppearedActivity(mActivity); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); final TaskFragmentContainer container = mSplitController.getContainerWithActivity( mActivity); Loading @@ -718,19 +721,38 @@ public class SplitControllerTest { primaryActivity); primaryContainer.addPendingAppearedActivity(mActivity); boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertFalse(result); assertEquals(primaryContainer, mSplitController.getContainerWithActivity(mActivity)); result = mSplitController.resolveActivityToContainer(mActivity, true /* canSplitAsPrimary */); result = mSplitController.resolveActivityToContainer(mActivity, true /* isOnReparent */); assertTrue(result); assertSplitPair(mActivity, primaryActivity); } @Test public void testGetPlaceholderOptions() { doReturn(true).when(mActivity).isResumed(); assertNull(mSplitController.getPlaceholderOptions(mActivity, false /* isOnCreated */)); doReturn(false).when(mActivity).isResumed(); assertNull(mSplitController.getPlaceholderOptions(mActivity, true /* isOnCreated */)); // Launch placeholder without moving the Task to front if the Task is now in background (not // resumed or onCreated). final Bundle options = mSplitController.getPlaceholderOptions(mActivity, false /* isOnCreated */); assertNotNull(options); final ActivityOptions activityOptions = new ActivityOptions(options); assertTrue(activityOptions.getAvoidMoveToFront()); } /** Creates a mock activity in the organizer process. */ private Activity createMockActivity() { final Activity activity = mock(Activity.class); Loading Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +43 −23 Original line number Diff line number Diff line Loading @@ -241,7 +241,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // launching to top. We allow split as primary for activity reparent because the // activity may be split as primary before it is reparented out. In that case, we want // to show it as primary again when it is reparented back. if (!resolveActivityToContainer(activity, true /* canSplitAsPrimary */)) { if (!resolveActivityToContainer(activity, true /* isOnReparent */)) { // When there is no embedding rule matched, try to place it in the top container // like a normal launch. placeActivityInTopContainer(activity); Loading Loading @@ -353,21 +353,21 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen void onActivityCreated(@NonNull Activity launchedActivity) { // TODO(b/229680885): we don't support launching into primary yet because we want to always // launch the new activity on top. resolveActivityToContainer(launchedActivity, false /* canSplitAsPrimary */); resolveActivityToContainer(launchedActivity, false /* isOnReparent */); updateCallbackIfNecessary(); } /** * Checks if the new added activity should be routed to a particular container. It can create a * new container for the activity and a new split container if necessary. * @param launchedActivity the new launched activity. * @param canSplitAsPrimary whether we can put the new launched activity into primary split. * @param activity the activity that is newly added to the Task. * @param isOnReparent whether the activity is reparented to the Task instead of new launched. * We only support to split as primary for reparented activity for now. * @return {@code true} if the activity was placed in TaskFragment container. */ @VisibleForTesting boolean resolveActivityToContainer(@NonNull Activity launchedActivity, boolean canSplitAsPrimary) { if (isInPictureInPicture(launchedActivity) || launchedActivity.isFinishing()) { boolean resolveActivityToContainer(@NonNull Activity activity, boolean isOnReparent) { if (isInPictureInPicture(activity) || activity.isFinishing()) { // We don't embed activity when it is in PIP, or finishing. Return true since we don't // want any extra handling. return true; Loading @@ -385,33 +385,32 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen */ // 1. Whether the new launched activity should always expand. if (shouldExpand(launchedActivity, null /* intent */)) { expandActivity(launchedActivity); if (shouldExpand(activity, null /* intent */)) { expandActivity(activity); return true; } // 2. Whether the new launched activity should launch a placeholder. if (launchPlaceholderIfNecessary(launchedActivity)) { if (launchPlaceholderIfNecessary(activity, !isOnReparent)) { return true; } // 3. Whether the new launched activity has already been in a split with a rule matched. if (isNewActivityInSplitWithRuleMatched(launchedActivity)) { if (isNewActivityInSplitWithRuleMatched(activity)) { return true; } // 4. Whether the activity below (if any) should be split with the new launched activity. final Activity activityBelow = findActivityBelow(launchedActivity); final Activity activityBelow = findActivityBelow(activity); if (activityBelow == null) { // Can't find any activity below. return false; } if (putActivitiesIntoSplitIfNecessary(activityBelow, launchedActivity)) { if (putActivitiesIntoSplitIfNecessary(activityBelow, activity)) { // Have split rule of [ activityBelow | launchedActivity ]. return true; } if (canSplitAsPrimary && putActivitiesIntoSplitIfNecessary(launchedActivity, activityBelow)) { if (isOnReparent && putActivitiesIntoSplitIfNecessary(activity, activityBelow)) { // Have split rule of [ launchedActivity | activityBelow]. return true; } Loading @@ -430,17 +429,16 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen ? topSplit.getSecondaryContainer() : topSplit.getPrimaryContainer(); final Activity otherTopActivity = otherTopContainer.getTopNonFinishingActivity(); if (otherTopActivity == null || otherTopActivity == launchedActivity) { if (otherTopActivity == null || otherTopActivity == activity) { // Can't find the top activity on the other split TaskFragment. return false; } if (putActivitiesIntoSplitIfNecessary(otherTopActivity, launchedActivity)) { if (putActivitiesIntoSplitIfNecessary(otherTopActivity, activity)) { // Have split rule of [ otherTopActivity | launchedActivity ]. return true; } // Have split rule of [ launchedActivity | otherTopActivity]. return canSplitAsPrimary && putActivitiesIntoSplitIfNecessary(launchedActivity, otherTopActivity); return isOnReparent && putActivitiesIntoSplitIfNecessary(activity, otherTopActivity); } /** Loading Loading @@ -603,7 +601,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } // Check if activity requires a placeholder launchPlaceholderIfNecessary(activity); launchPlaceholderIfNecessary(activity, false /* isOnCreated */); } @VisibleForTesting Loading Loading @@ -1043,10 +1041,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return false; } return launchPlaceholderIfNecessary(topActivity); return launchPlaceholderIfNecessary(topActivity, false /* isOnCreated */); } boolean launchPlaceholderIfNecessary(@NonNull Activity activity) { boolean launchPlaceholderIfNecessary(@NonNull Activity activity, boolean isOnCreated) { final TaskFragmentContainer container = getContainerWithActivity(activity); // Don't launch placeholder if the container is occluded. if (container != null && container != getTopActiveContainer(container.getTaskId())) { Loading @@ -1067,11 +1065,33 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } // TODO(b/190433398): Handle failed request startActivityToSide(activity, placeholderRule.getPlaceholderIntent(), null /* options */, final Bundle options = getPlaceholderOptions(activity, isOnCreated); startActivityToSide(activity, placeholderRule.getPlaceholderIntent(), options, placeholderRule, null /* failureCallback */, true /* isPlaceholder */); return true; } /** * Gets the activity options for starting the placeholder activity. In case the placeholder is * launched when the Task is in the background, we don't want to bring the Task to the front. * @param primaryActivity the primary activity to launch the placeholder from. * @param isOnCreated whether this happens during the primary activity onCreated. */ @VisibleForTesting @Nullable Bundle getPlaceholderOptions(@NonNull Activity primaryActivity, boolean isOnCreated) { // Setting avoid move to front will also skip the animation. We only want to do that when // the Task is currently in background. // Check if the primary is resumed or if this is called when the primary is onCreated // (not resumed yet). if (isOnCreated || primaryActivity.isResumed()) { return null; } final ActivityOptions options = ActivityOptions.makeBasic(); options.setAvoidMoveToFront(); return options.toBundle(); } @VisibleForTesting boolean dismissPlaceholderIfNecessary(@NonNull SplitContainer splitContainer) { if (!splitContainer.isPlaceholderContainer()) { Loading
libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java +51 −29 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ import static org.mockito.Mockito.never; import android.annotation.NonNull; import android.app.Activity; import android.app.ActivityOptions; import android.content.ComponentName; import android.content.Intent; import android.content.res.Configuration; Loading @@ -50,6 +51,7 @@ import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.platform.test.annotations.Presubmit; Loading Loading @@ -219,7 +221,8 @@ public class SplitControllerTest { spyOn(tf); doReturn(mActivity).when(tf).getTopNonFinishingActivity(); doReturn(true).when(tf).isEmpty(); doReturn(true).when(mSplitController).launchPlaceholderIfNecessary(mActivity); doReturn(true).when(mSplitController).launchPlaceholderIfNecessary(mActivity, false /* isOnCreated */); doNothing().when(mSplitPresenter).updateSplitContainer(any(), any(), any()); mSplitController.updateContainer(mTransaction, tf); Loading Loading @@ -287,8 +290,7 @@ public class SplitControllerTest { mSplitController.onActivityCreated(mActivity); // Disallow to split as primary because we want the new launch to be always on top. verify(mSplitController).resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); verify(mSplitController).resolveActivityToContainer(mActivity, false /* isOnReparent */); } @Test Loading @@ -297,8 +299,7 @@ public class SplitControllerTest { mActivity.getActivityToken()); // Treated as on activity created, but allow to split as primary. verify(mSplitController).resolveActivityToContainer(mActivity, true /* canSplitAsPrimary */); verify(mSplitController).resolveActivityToContainer(mActivity, true /* isOnReparent */); // Try to place the activity to the top TaskFragment when there is no matched rule. verify(mSplitController).placeActivityInTopContainer(mActivity); } Loading Loading @@ -432,7 +433,7 @@ public class SplitControllerTest { @Test public void testResolveActivityToContainer_noRuleMatched() { final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertFalse(result); verify(mSplitController, never()).newContainer(any(), any(), anyInt()); Loading @@ -444,7 +445,7 @@ public class SplitControllerTest { // When the activity is not in any TaskFragment, create a new expanded TaskFragment for it. final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); final TaskFragmentContainer container = mSplitController.getContainerWithActivity( mActivity); Loading @@ -461,7 +462,7 @@ public class SplitControllerTest { // When the activity is not in any TaskFragment, create a new expanded TaskFragment for it. final TaskFragmentContainer container = mSplitController.newContainer(mActivity, TASK_ID); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertTrue(result); verify(mSplitPresenter).expandTaskFragment(container.getTaskFragmentToken()); Loading @@ -475,7 +476,7 @@ public class SplitControllerTest { final Activity activity = createMockActivity(); addSplitTaskFragments(activity, mActivity); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); final TaskFragmentContainer container = mSplitController.getContainerWithActivity( mActivity); Loading @@ -492,11 +493,12 @@ public class SplitControllerTest { // Launch placeholder if the activity is not in any TaskFragment. final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertTrue(result); verify(mSplitPresenter).startActivityToSide(mActivity, PLACEHOLDER_INTENT, null /* activityOptions */, placeholderRule, true /* isPlaceholder */); mSplitController.getPlaceholderOptions(mActivity, true /* isOnCreated */), placeholderRule, true /* isPlaceholder */); } @Test Loading @@ -508,7 +510,7 @@ public class SplitControllerTest { mSplitController.newContainer(mActivity, TASK_ID); mSplitController.newContainer(activity, TASK_ID); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertFalse(result); verify(mSplitPresenter, never()).startActivityToSide(any(), any(), any(), any(), Loading @@ -524,11 +526,12 @@ public class SplitControllerTest { // Launch placeholder if the activity is in the topmost expanded TaskFragment. mSplitController.newContainer(mActivity, TASK_ID); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertTrue(result); verify(mSplitPresenter).startActivityToSide(mActivity, PLACEHOLDER_INTENT, null /* activityOptions */, placeholderRule, true /* isPlaceholder */); mSplitController.getPlaceholderOptions(mActivity, true /* isOnCreated */), placeholderRule, true /* isPlaceholder */); } @Test Loading @@ -539,7 +542,7 @@ public class SplitControllerTest { final Activity secondaryActivity = createMockActivity(); addSplitTaskFragments(mActivity, secondaryActivity); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertFalse(result); verify(mSplitPresenter, never()).startActivityToSide(any(), any(), any(), any(), Loading @@ -556,11 +559,12 @@ public class SplitControllerTest { final Activity primaryActivity = createMockActivity(); addSplitTaskFragments(primaryActivity, mActivity); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertTrue(result); verify(mSplitPresenter).startActivityToSide(mActivity, PLACEHOLDER_INTENT, null /* activityOptions */, placeholderRule, true /* isPlaceholder */); mSplitController.getPlaceholderOptions(mActivity, true /* isOnCreated */), placeholderRule, true /* isPlaceholder */); } @Test Loading @@ -582,7 +586,7 @@ public class SplitControllerTest { splitRule); clearInvocations(mSplitController); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertTrue(result); verify(mSplitController, never()).newContainer(any(), any(), anyInt()); Loading @@ -598,7 +602,7 @@ public class SplitControllerTest { addSplitTaskFragments(primaryActivity, mActivity); clearInvocations(mSplitController); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertTrue(result); verify(mSplitController, never()).newContainer(any(), any(), anyInt()); Loading @@ -616,7 +620,7 @@ public class SplitControllerTest { mSplitController.getContainerWithActivity(secondaryActivity) .addPendingAppearedActivity(mActivity); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertFalse(result); } Loading @@ -641,7 +645,7 @@ public class SplitControllerTest { secondaryContainer, placeholderRule); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertTrue(result); } Loading @@ -655,7 +659,7 @@ public class SplitControllerTest { TASK_ID); container.addPendingAppearedActivity(mActivity); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertTrue(result); assertSplitPair(activityBelow, mActivity); Loading @@ -671,14 +675,13 @@ public class SplitControllerTest { TASK_ID); container.addPendingAppearedActivity(mActivity); boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertFalse(result); assertEquals(container, mSplitController.getContainerWithActivity(mActivity)); // Allow to split as primary. result = mSplitController.resolveActivityToContainer(mActivity, true /* canSplitAsPrimary */); result = mSplitController.resolveActivityToContainer(mActivity, true /* isOnReparent */); assertTrue(result); assertSplitPair(mActivity, activityBelow); Loading @@ -697,7 +700,7 @@ public class SplitControllerTest { activityBelow); secondaryContainer.addPendingAppearedActivity(mActivity); final boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); final TaskFragmentContainer container = mSplitController.getContainerWithActivity( mActivity); Loading @@ -718,19 +721,38 @@ public class SplitControllerTest { primaryActivity); primaryContainer.addPendingAppearedActivity(mActivity); boolean result = mSplitController.resolveActivityToContainer(mActivity, false /* canSplitAsPrimary */); false /* isOnReparent */); assertFalse(result); assertEquals(primaryContainer, mSplitController.getContainerWithActivity(mActivity)); result = mSplitController.resolveActivityToContainer(mActivity, true /* canSplitAsPrimary */); result = mSplitController.resolveActivityToContainer(mActivity, true /* isOnReparent */); assertTrue(result); assertSplitPair(mActivity, primaryActivity); } @Test public void testGetPlaceholderOptions() { doReturn(true).when(mActivity).isResumed(); assertNull(mSplitController.getPlaceholderOptions(mActivity, false /* isOnCreated */)); doReturn(false).when(mActivity).isResumed(); assertNull(mSplitController.getPlaceholderOptions(mActivity, true /* isOnCreated */)); // Launch placeholder without moving the Task to front if the Task is now in background (not // resumed or onCreated). final Bundle options = mSplitController.getPlaceholderOptions(mActivity, false /* isOnCreated */); assertNotNull(options); final ActivityOptions activityOptions = new ActivityOptions(options); assertTrue(activityOptions.getAvoidMoveToFront()); } /** Creates a mock activity in the organizer process. */ private Activity createMockActivity() { final Activity activity = mock(Activity.class); Loading