Merge "Allow launching placeholder when the TaskFragment is visible" into tm-qpr-dev

This commit is contained in:
TreeHugger Robot
2022-12-15 17:12:27 +00:00
committed by Android (Google) Code Review
7 changed files with 139 additions and 25 deletions

View File

@@ -425,12 +425,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
if (container != null) {
// Cleanup if the TaskFragment vanished is not requested by the organizer.
removeContainer(container);
// Make sure the top container is updated.
final TaskFragmentContainer newTopContainer = getTopActiveContainer(
container.getTaskId());
if (newTopContainer != null) {
updateContainer(wct, newTopContainer);
}
// Make sure the containers in the Task are up-to-date.
updateContainersInTaskIfVisible(wct, container.getTaskId());
}
cleanupTaskFragment(taskFragmentInfo.getFragmentToken());
}
@@ -470,6 +466,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
updateContainersInTask(wct, taskContainer);
}
void updateContainersInTaskIfVisible(@NonNull WindowContainerTransaction wct, int taskId) {
final TaskContainer taskContainer = getTaskContainer(taskId);
if (taskContainer != null && taskContainer.isVisible()) {
updateContainersInTask(wct, taskContainer);
}
}
private void updateContainersInTask(@NonNull WindowContainerTransaction wct,
@NonNull TaskContainer taskContainer) {
// Update all TaskFragments in the Task. Make a copy of the list since some may be
@@ -1320,9 +1323,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
void removeContainer(@NonNull TaskFragmentContainer container) {
// Remove all split containers that included this one
final TaskContainer taskContainer = container.getTaskContainer();
if (taskContainer == null) {
return;
}
taskContainer.mContainers.remove(container);
// Marked as a pending removal which will be removed after it is actually removed on the
// server side (#onTaskFragmentVanished).
@@ -1515,14 +1515,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
final TaskFragmentContainer container = getContainerWithActivity(activity);
// Don't launch placeholder if the container is occluded.
if (container != null && container != getTopActiveContainer(container.getTaskId())) {
return false;
}
final SplitContainer splitContainer = getActiveSplitForContainer(container);
if (splitContainer != null && container.equals(splitContainer.getPrimaryContainer())) {
// Don't launch placeholder in primary split container
if (container != null && !allowLaunchPlaceholder(container)) {
// We don't allow activity in this TaskFragment to launch placeholder.
return false;
}
@@ -1550,6 +1544,32 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return true;
}
/** Whether or not to allow activity in this container to launch placeholder. */
@GuardedBy("mLock")
private boolean allowLaunchPlaceholder(@NonNull TaskFragmentContainer container) {
final TaskFragmentContainer topContainer = getTopActiveContainer(container.getTaskId());
if (container != topContainer) {
// The container is not the top most.
if (!container.isVisible()) {
// In case the container is visible (the one on top may be transparent), we may
// still want to launch placeholder even if it is not the top most.
return false;
}
if (topContainer.isWaitingActivityAppear()) {
// When the top container appeared info is not sent by the server yet, the visible
// check above may not be reliable.
return false;
}
}
final SplitContainer splitContainer = getActiveSplitForContainer(container);
if (splitContainer != null && container.equals(splitContainer.getPrimaryContainer())) {
// Don't launch placeholder for primary split container.
return false;
}
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.

View File

@@ -154,12 +154,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
void cleanupContainer(@NonNull WindowContainerTransaction wct,
@NonNull TaskFragmentContainer container, boolean shouldFinishDependent) {
container.finish(shouldFinishDependent, this, wct, mController);
final TaskFragmentContainer newTopContainer = mController.getTopActiveContainer(
container.getTaskId());
if (newTopContainer != null) {
mController.updateContainer(wct, newTopContainer);
}
// Make sure the containers in the Task is up-to-date.
mController.updateContainersInTaskIfVisible(wct, container.getTaskId());
}
/**

View File

@@ -184,6 +184,11 @@ class TaskFragmentContainer {
return allActivities;
}
/** Whether this TaskFragment is visible. */
boolean isVisible() {
return mInfo != null && mInfo.isVisible();
}
/** Whether the TaskFragment is in an intermediate state waiting for the server update.*/
boolean isInIntermediateState() {
if (mInfo == null) {

View File

@@ -163,11 +163,17 @@ public class EmbeddingTestUtils {
/** Creates a mock TaskFragmentInfo for the given TaskFragment. */
static TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container,
@NonNull Activity activity) {
return createMockTaskFragmentInfo(container, activity, true /* isVisible */);
}
/** Creates a mock TaskFragmentInfo for the given TaskFragment. */
static TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container,
@NonNull Activity activity, boolean isVisible) {
return new TaskFragmentInfo(container.getTaskFragmentToken(),
mock(WindowContainerToken.class),
new Configuration(),
1,
true /* isVisible */,
isVisible,
Collections.singletonList(activity.getActivityToken()),
new Point(),
false /* isTaskClearedForReuse */,

View File

@@ -1254,6 +1254,68 @@ public class SplitControllerTest {
verify(mEmbeddingCallback).accept(any());
}
@Test
public void testLaunchPlaceholderIfNecessary_nonEmbeddedActivity() {
// Launch placeholder for non embedded activity.
setupPlaceholderRule(mActivity);
mTransactionManager.startNewTransaction();
mSplitController.launchPlaceholderIfNecessary(mTransaction, mActivity,
true /* isOnCreated */);
verify(mTransaction).startActivityInTaskFragment(any(), any(), eq(PLACEHOLDER_INTENT),
any());
}
@Test
public void testLaunchPlaceholderIfNecessary_embeddedInTopTaskFragment() {
// Launch placeholder for activity in top TaskFragment.
setupPlaceholderRule(mActivity);
mTransactionManager.startNewTransaction();
final TaskFragmentContainer container = mSplitController.newContainer(mActivity, TASK_ID);
mSplitController.launchPlaceholderIfNecessary(mTransaction, mActivity,
true /* isOnCreated */);
assertTrue(container.hasActivity(mActivity.getActivityToken()));
verify(mTransaction).startActivityInTaskFragment(any(), any(), eq(PLACEHOLDER_INTENT),
any());
}
@Test
public void testLaunchPlaceholderIfNecessary_embeddedBelowTaskFragment() {
// Do not launch placeholder for invisible activity below the top TaskFragment.
setupPlaceholderRule(mActivity);
mTransactionManager.startNewTransaction();
final TaskFragmentContainer bottomTf = mSplitController.newContainer(mActivity, TASK_ID);
final TaskFragmentContainer topTf = mSplitController.newContainer(new Intent(), mActivity,
TASK_ID);
bottomTf.setInfo(mTransaction, createMockTaskFragmentInfo(bottomTf, mActivity,
false /* isVisible */));
topTf.setInfo(mTransaction, createMockTaskFragmentInfo(topTf, createMockActivity()));
assertFalse(bottomTf.isVisible());
mSplitController.launchPlaceholderIfNecessary(mTransaction, mActivity,
true /* isOnCreated */);
verify(mTransaction, never()).startActivityInTaskFragment(any(), any(), any(), any());
}
@Test
public void testLaunchPlaceholderIfNecessary_embeddedBelowTransparentTaskFragment() {
// Launch placeholder for visible activity below the top TaskFragment.
setupPlaceholderRule(mActivity);
mTransactionManager.startNewTransaction();
final TaskFragmentContainer bottomTf = mSplitController.newContainer(mActivity, TASK_ID);
final TaskFragmentContainer topTf = mSplitController.newContainer(new Intent(), mActivity,
TASK_ID);
bottomTf.setInfo(mTransaction, createMockTaskFragmentInfo(bottomTf, mActivity,
true /* isVisible */));
topTf.setInfo(mTransaction, createMockTaskFragmentInfo(topTf, createMockActivity()));
assertTrue(bottomTf.isVisible());
mSplitController.launchPlaceholderIfNecessary(mTransaction, mActivity,
true /* isOnCreated */);
verify(mTransaction).startActivityInTaskFragment(any(), any(), any(), any());
}
/** Creates a mock activity in the organizer process. */
private Activity createMockActivity() {
return createMockActivity(TASK_ID);

View File

@@ -500,6 +500,29 @@ public class TaskFragmentContainerTest {
assertEquals(2, taskContainer.indexOf(tf1));
}
@Test
public void testIsVisible() {
final TaskContainer taskContainer = createTestTaskContainer();
final TaskFragmentContainer container = new TaskFragmentContainer(
null /* pendingAppearedActivity */, new Intent(), taskContainer, mController,
null /* pairedPrimaryTaskFragment */);
// Not visible when there is not appeared.
assertFalse(container.isVisible());
// Respect info.isVisible.
TaskFragmentInfo info = createMockTaskFragmentInfo(container, mActivity,
true /* isVisible */);
container.setInfo(mTransaction, info);
assertTrue(container.isVisible());
info = createMockTaskFragmentInfo(container, mActivity, false /* isVisible */);
container.setInfo(mTransaction, info);
assertFalse(container.isVisible());
}
/** Creates a mock activity in the organizer process. */
private Activity createMockActivity() {
final Activity activity = mock(Activity.class);

View File

@@ -2553,7 +2553,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
mRemoteToken.toWindowContainerToken(),
getConfiguration(),
getNonFinishingActivityCount(),
isVisibleRequested(),
shouldBeVisible(null /* starting */),
childActivities,
positionInParent,
mClearedTaskForReuse,
@@ -2849,6 +2849,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
if (parentTf != null) {
parentTf.onActivityVisibleRequestedChanged();
}
// Send the info changed to update the TaskFragment visibility.
sendTaskFragmentInfoChanged();
}
@Nullable