Merge "Allow launching placeholder when the TaskFragment is visible" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
04f120732a
@@ -425,12 +425,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
if (container != null) {
|
if (container != null) {
|
||||||
// Cleanup if the TaskFragment vanished is not requested by the organizer.
|
// Cleanup if the TaskFragment vanished is not requested by the organizer.
|
||||||
removeContainer(container);
|
removeContainer(container);
|
||||||
// Make sure the top container is updated.
|
// Make sure the containers in the Task are up-to-date.
|
||||||
final TaskFragmentContainer newTopContainer = getTopActiveContainer(
|
updateContainersInTaskIfVisible(wct, container.getTaskId());
|
||||||
container.getTaskId());
|
|
||||||
if (newTopContainer != null) {
|
|
||||||
updateContainer(wct, newTopContainer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
cleanupTaskFragment(taskFragmentInfo.getFragmentToken());
|
cleanupTaskFragment(taskFragmentInfo.getFragmentToken());
|
||||||
}
|
}
|
||||||
@@ -470,6 +466,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
updateContainersInTask(wct, taskContainer);
|
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,
|
private void updateContainersInTask(@NonNull WindowContainerTransaction wct,
|
||||||
@NonNull TaskContainer taskContainer) {
|
@NonNull TaskContainer taskContainer) {
|
||||||
// Update all TaskFragments in the Task. Make a copy of the list since some may be
|
// 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) {
|
void removeContainer(@NonNull TaskFragmentContainer container) {
|
||||||
// Remove all split containers that included this one
|
// Remove all split containers that included this one
|
||||||
final TaskContainer taskContainer = container.getTaskContainer();
|
final TaskContainer taskContainer = container.getTaskContainer();
|
||||||
if (taskContainer == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
taskContainer.mContainers.remove(container);
|
taskContainer.mContainers.remove(container);
|
||||||
// Marked as a pending removal which will be removed after it is actually removed on the
|
// Marked as a pending removal which will be removed after it is actually removed on the
|
||||||
// server side (#onTaskFragmentVanished).
|
// server side (#onTaskFragmentVanished).
|
||||||
@@ -1515,14 +1515,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
}
|
}
|
||||||
|
|
||||||
final TaskFragmentContainer container = getContainerWithActivity(activity);
|
final TaskFragmentContainer container = getContainerWithActivity(activity);
|
||||||
// Don't launch placeholder if the container is occluded.
|
if (container != null && !allowLaunchPlaceholder(container)) {
|
||||||
if (container != null && container != getTopActiveContainer(container.getTaskId())) {
|
// We don't allow activity in this TaskFragment to launch placeholder.
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final SplitContainer splitContainer = getActiveSplitForContainer(container);
|
|
||||||
if (splitContainer != null && container.equals(splitContainer.getPrimaryContainer())) {
|
|
||||||
// Don't launch placeholder in primary split container
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1550,6 +1544,32 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
return true;
|
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
|
* 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.
|
* launched when the Task is in the background, we don't want to bring the Task to the front.
|
||||||
|
|||||||
@@ -154,12 +154,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
|
|||||||
void cleanupContainer(@NonNull WindowContainerTransaction wct,
|
void cleanupContainer(@NonNull WindowContainerTransaction wct,
|
||||||
@NonNull TaskFragmentContainer container, boolean shouldFinishDependent) {
|
@NonNull TaskFragmentContainer container, boolean shouldFinishDependent) {
|
||||||
container.finish(shouldFinishDependent, this, wct, mController);
|
container.finish(shouldFinishDependent, this, wct, mController);
|
||||||
|
// Make sure the containers in the Task is up-to-date.
|
||||||
final TaskFragmentContainer newTopContainer = mController.getTopActiveContainer(
|
mController.updateContainersInTaskIfVisible(wct, container.getTaskId());
|
||||||
container.getTaskId());
|
|
||||||
if (newTopContainer != null) {
|
|
||||||
mController.updateContainer(wct, newTopContainer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -184,6 +184,11 @@ class TaskFragmentContainer {
|
|||||||
return allActivities;
|
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.*/
|
/** Whether the TaskFragment is in an intermediate state waiting for the server update.*/
|
||||||
boolean isInIntermediateState() {
|
boolean isInIntermediateState() {
|
||||||
if (mInfo == null) {
|
if (mInfo == null) {
|
||||||
|
|||||||
@@ -163,11 +163,17 @@ public class EmbeddingTestUtils {
|
|||||||
/** Creates a mock TaskFragmentInfo for the given TaskFragment. */
|
/** Creates a mock TaskFragmentInfo for the given TaskFragment. */
|
||||||
static TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container,
|
static TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container,
|
||||||
@NonNull Activity activity) {
|
@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(),
|
return new TaskFragmentInfo(container.getTaskFragmentToken(),
|
||||||
mock(WindowContainerToken.class),
|
mock(WindowContainerToken.class),
|
||||||
new Configuration(),
|
new Configuration(),
|
||||||
1,
|
1,
|
||||||
true /* isVisible */,
|
isVisible,
|
||||||
Collections.singletonList(activity.getActivityToken()),
|
Collections.singletonList(activity.getActivityToken()),
|
||||||
new Point(),
|
new Point(),
|
||||||
false /* isTaskClearedForReuse */,
|
false /* isTaskClearedForReuse */,
|
||||||
|
|||||||
@@ -1254,6 +1254,68 @@ public class SplitControllerTest {
|
|||||||
verify(mEmbeddingCallback).accept(any());
|
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. */
|
/** Creates a mock activity in the organizer process. */
|
||||||
private Activity createMockActivity() {
|
private Activity createMockActivity() {
|
||||||
return createMockActivity(TASK_ID);
|
return createMockActivity(TASK_ID);
|
||||||
|
|||||||
@@ -500,6 +500,29 @@ public class TaskFragmentContainerTest {
|
|||||||
assertEquals(2, taskContainer.indexOf(tf1));
|
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. */
|
/** Creates a mock activity in the organizer process. */
|
||||||
private Activity createMockActivity() {
|
private Activity createMockActivity() {
|
||||||
final Activity activity = mock(Activity.class);
|
final Activity activity = mock(Activity.class);
|
||||||
|
|||||||
@@ -2553,7 +2553,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
|||||||
mRemoteToken.toWindowContainerToken(),
|
mRemoteToken.toWindowContainerToken(),
|
||||||
getConfiguration(),
|
getConfiguration(),
|
||||||
getNonFinishingActivityCount(),
|
getNonFinishingActivityCount(),
|
||||||
isVisibleRequested(),
|
shouldBeVisible(null /* starting */),
|
||||||
childActivities,
|
childActivities,
|
||||||
positionInParent,
|
positionInParent,
|
||||||
mClearedTaskForReuse,
|
mClearedTaskForReuse,
|
||||||
@@ -2849,6 +2849,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
|
|||||||
if (parentTf != null) {
|
if (parentTf != null) {
|
||||||
parentTf.onActivityVisibleRequestedChanged();
|
parentTf.onActivityVisibleRequestedChanged();
|
||||||
}
|
}
|
||||||
|
// Send the info changed to update the TaskFragment visibility.
|
||||||
|
sendTaskFragmentInfoChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
Reference in New Issue
Block a user