Merge "Don't bring the Task to front when launching placeholder in background" into tm-dev
This commit is contained in:
@@ -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);
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -603,7 +601,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
}
|
||||
|
||||
// Check if activity requires a placeholder
|
||||
launchPlaceholderIfNecessary(activity);
|
||||
launchPlaceholderIfNecessary(activity, false /* isOnCreated */);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -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())) {
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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());
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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(),
|
||||
@@ -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
|
||||
@@ -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(),
|
||||
@@ -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
|
||||
@@ -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());
|
||||
@@ -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());
|
||||
@@ -616,7 +620,7 @@ public class SplitControllerTest {
|
||||
mSplitController.getContainerWithActivity(secondaryActivity)
|
||||
.addPendingAppearedActivity(mActivity);
|
||||
final boolean result = mSplitController.resolveActivityToContainer(mActivity,
|
||||
false /* canSplitAsPrimary */);
|
||||
false /* isOnReparent */);
|
||||
|
||||
assertFalse(result);
|
||||
}
|
||||
@@ -641,7 +645,7 @@ public class SplitControllerTest {
|
||||
secondaryContainer,
|
||||
placeholderRule);
|
||||
final boolean result = mSplitController.resolveActivityToContainer(mActivity,
|
||||
false /* canSplitAsPrimary */);
|
||||
false /* isOnReparent */);
|
||||
|
||||
assertTrue(result);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user