[2/n] Pin ActivityStack
Make TaskContainer#mContainers private. This is a preliminary step of handling the pinning container in the following CLs. Noted that the #getTaskFragmentContainers and #getSplitContainers returns the real list to improve the efficiency, but we shouldn't make modifications on the returned list directly. Bug: 208573140 Test: atest SplitControllerTest TaskContainerTest Change-Id: Ia5b298c402f287777c2cbdd4fb1bb23c8c5102b7
This commit is contained in:
@@ -308,7 +308,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
|
||||
forAllTaskContainers(taskContainer -> {
|
||||
synchronized (mLock) {
|
||||
final List<TaskFragmentContainer> containers = taskContainer.mContainers;
|
||||
final List<TaskFragmentContainer> containers =
|
||||
taskContainer.getTaskFragmentContainers();
|
||||
// Clean up the TaskFragmentContainers by the z-order from the lowest.
|
||||
for (int i = 0; i < containers.size(); i++) {
|
||||
final TaskFragmentContainer container = containers.get(i);
|
||||
@@ -611,8 +612,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
@NonNull TaskContainer taskContainer) {
|
||||
// Update all TaskFragments in the Task. Make a copy of the list since some may be
|
||||
// removed on updating.
|
||||
final List<TaskFragmentContainer> containers =
|
||||
new ArrayList<>(taskContainer.mContainers);
|
||||
final List<TaskFragmentContainer> containers = taskContainer.getTaskFragmentContainers();
|
||||
for (int i = containers.size() - 1; i >= 0; i--) {
|
||||
final TaskFragmentContainer container = containers.get(i);
|
||||
// Wait until onTaskFragmentAppeared to update new container.
|
||||
@@ -1331,7 +1331,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
// Check pending appeared activity first because there can be a delay for the server
|
||||
// update.
|
||||
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
|
||||
final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
|
||||
final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i)
|
||||
.getTaskFragmentContainers();
|
||||
for (int j = containers.size() - 1; j >= 0; j--) {
|
||||
final TaskFragmentContainer container = containers.get(j);
|
||||
if (container.hasPendingAppearedActivity(activityToken)) {
|
||||
@@ -1342,7 +1343,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
|
||||
// Check appeared activity if there is no such pending appeared activity.
|
||||
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
|
||||
final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
|
||||
final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i)
|
||||
.getTaskFragmentContainers();
|
||||
for (int j = containers.size() - 1; j >= 0; j--) {
|
||||
final TaskFragmentContainer container = containers.get(j);
|
||||
if (container.hasAppearedActivity(activityToken)) {
|
||||
@@ -1472,7 +1474,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
void removeContainers(@NonNull TaskContainer taskContainer,
|
||||
@NonNull List<TaskFragmentContainer> containers) {
|
||||
// Remove all split containers that included this one
|
||||
taskContainer.mContainers.removeAll(containers);
|
||||
taskContainer.removeTaskFragmentContainers(containers);
|
||||
// Marked as a pending removal which will be removed after it is actually removed on the
|
||||
// server side (#onTaskFragmentVanished).
|
||||
// In this way, we can keep track of the Task bounds until we no longer have any
|
||||
@@ -1497,7 +1499,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
taskContainer.removeSplitContainers(containersToRemove);
|
||||
|
||||
// Cleanup any dependent references.
|
||||
for (TaskFragmentContainer containerToUpdate : taskContainer.mContainers) {
|
||||
final List<TaskFragmentContainer> taskFragmentContainers =
|
||||
taskContainer.getTaskFragmentContainers();
|
||||
for (TaskFragmentContainer containerToUpdate : taskFragmentContainers) {
|
||||
containerToUpdate.removeContainersToFinishOnExit(containers);
|
||||
}
|
||||
}
|
||||
@@ -1536,8 +1540,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
if (taskContainer == null) {
|
||||
return null;
|
||||
}
|
||||
for (int i = taskContainer.mContainers.size() - 1; i >= 0; i--) {
|
||||
final TaskFragmentContainer container = taskContainer.mContainers.get(i);
|
||||
final List<TaskFragmentContainer> containers = taskContainer.getTaskFragmentContainers();
|
||||
for (int i = containers.size() - 1; i >= 0; i--) {
|
||||
final TaskFragmentContainer container = containers.get(i);
|
||||
if (!container.isFinished() && (container.getRunningActivityCount() > 0
|
||||
// We may be waiting for the top TaskFragment to become non-empty after
|
||||
// creation. In that case, we don't want to treat the TaskFragment below it as
|
||||
@@ -1933,7 +1938,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
@GuardedBy("mLock")
|
||||
TaskFragmentContainer getContainer(@NonNull IBinder fragmentToken) {
|
||||
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
|
||||
final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
|
||||
final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i)
|
||||
.getTaskFragmentContainers();
|
||||
for (TaskFragmentContainer container : containers) {
|
||||
if (container.getTaskFragmentToken().equals(fragmentToken)) {
|
||||
return container;
|
||||
@@ -2094,7 +2100,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
}
|
||||
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
|
||||
final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i)
|
||||
.mContainers;
|
||||
.getTaskFragmentContainers();
|
||||
for (int j = containers.size() - 1; j >= 0; j--) {
|
||||
final TaskFragmentContainer container = containers.get(j);
|
||||
if (!container.hasActivity(activityToken)
|
||||
|
||||
@@ -51,7 +51,7 @@ class TaskContainer {
|
||||
|
||||
/** Active TaskFragments in this Task. */
|
||||
@NonNull
|
||||
final List<TaskFragmentContainer> mContainers = new ArrayList<>();
|
||||
private final List<TaskFragmentContainer> mContainers = new ArrayList<>();
|
||||
|
||||
/** Active split pairs in this Task. */
|
||||
@NonNull
|
||||
@@ -207,9 +207,13 @@ class TaskContainer {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of {@link SplitContainer}. Do not modify the containers directly on the
|
||||
* returned list. Use {@link #addSplitContainer} or {@link #removeSplitContainers} instead.
|
||||
*/
|
||||
@NonNull
|
||||
List<SplitContainer> getSplitContainers() {
|
||||
return new ArrayList<>(mSplitContainers);
|
||||
return mSplitContainers;
|
||||
}
|
||||
|
||||
void addSplitContainer(@NonNull SplitContainer splitContainer) {
|
||||
@@ -220,6 +224,36 @@ class TaskContainer {
|
||||
mSplitContainers.removeAll(containers);
|
||||
}
|
||||
|
||||
void addTaskFragmentContainer(@NonNull TaskFragmentContainer taskFragmentContainer) {
|
||||
mContainers.add(taskFragmentContainer);
|
||||
}
|
||||
|
||||
void addTaskFragmentContainer(int index, @NonNull TaskFragmentContainer taskFragmentContainer) {
|
||||
mContainers.add(index, taskFragmentContainer);
|
||||
}
|
||||
|
||||
void removeTaskFragmentContainer(@NonNull TaskFragmentContainer taskFragmentContainer) {
|
||||
mContainers.remove(taskFragmentContainer);
|
||||
}
|
||||
|
||||
void removeTaskFragmentContainers(@NonNull List<TaskFragmentContainer> taskFragmentContainer) {
|
||||
mContainers.removeAll(taskFragmentContainer);
|
||||
}
|
||||
|
||||
void clearTaskFragmentContainer() {
|
||||
mContainers.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of {@link TaskFragmentContainer}. Do not modify the containers directly on
|
||||
* the returned list. Use {@link #addTaskFragmentContainer},
|
||||
* {@link #removeTaskFragmentContainer} or other related methods instead.
|
||||
*/
|
||||
@NonNull
|
||||
List<TaskFragmentContainer> getTaskFragmentContainers() {
|
||||
return mContainers;
|
||||
}
|
||||
|
||||
/** Adds the descriptors of split states in this Task to {@code outSplitStates}. */
|
||||
void getSplitStates(@NonNull List<SplitInfo> outSplitStates) {
|
||||
for (SplitContainer container : mSplitContainers) {
|
||||
|
||||
@@ -180,23 +180,25 @@ class TaskFragmentContainer {
|
||||
throw new IllegalArgumentException(
|
||||
"pairedPrimaryContainer must be in the same Task");
|
||||
}
|
||||
final int primaryIndex = taskContainer.mContainers.indexOf(pairedPrimaryContainer);
|
||||
taskContainer.mContainers.add(primaryIndex + 1, this);
|
||||
final int primaryIndex = taskContainer.indexOf(pairedPrimaryContainer);
|
||||
taskContainer.addTaskFragmentContainer(primaryIndex + 1, this);
|
||||
} else if (pendingAppearedActivity != null) {
|
||||
// The TaskFragment will be positioned right above the pending appeared Activity. If any
|
||||
// existing TaskFragment is empty with pending Intent, it is likely that the Activity of
|
||||
// the pending Intent hasn't been created yet, so the new Activity should be below the
|
||||
// empty TaskFragment.
|
||||
int i = taskContainer.mContainers.size() - 1;
|
||||
final List<TaskFragmentContainer> containers =
|
||||
taskContainer.getTaskFragmentContainers();
|
||||
int i = containers.size() - 1;
|
||||
for (; i >= 0; i--) {
|
||||
final TaskFragmentContainer container = taskContainer.mContainers.get(i);
|
||||
final TaskFragmentContainer container = containers.get(i);
|
||||
if (!container.isEmpty() || container.getPendingAppearedIntent() == null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
taskContainer.mContainers.add(i + 1, this);
|
||||
taskContainer.addTaskFragmentContainer(i + 1, this);
|
||||
} else {
|
||||
taskContainer.mContainers.add(this);
|
||||
taskContainer.addTaskFragmentContainer(this);
|
||||
}
|
||||
if (pendingAppearedActivity != null) {
|
||||
addPendingAppearedActivity(pendingAppearedActivity);
|
||||
|
||||
@@ -183,23 +183,23 @@ public class SplitControllerTest {
|
||||
// tf2 has running activity so is active.
|
||||
final TaskFragmentContainer tf2 = mock(TaskFragmentContainer.class);
|
||||
doReturn(1).when(tf2).getRunningActivityCount();
|
||||
taskContainer.mContainers.add(tf2);
|
||||
taskContainer.addTaskFragmentContainer(tf2);
|
||||
// tf3 is finished so is not active.
|
||||
final TaskFragmentContainer tf3 = mock(TaskFragmentContainer.class);
|
||||
doReturn(true).when(tf3).isFinished();
|
||||
doReturn(false).when(tf3).isWaitingActivityAppear();
|
||||
taskContainer.mContainers.add(tf3);
|
||||
taskContainer.addTaskFragmentContainer(tf3);
|
||||
mSplitController.mTaskContainers.put(TASK_ID, taskContainer);
|
||||
|
||||
assertWithMessage("Must return tf2 because tf3 is not active.")
|
||||
.that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf2);
|
||||
|
||||
taskContainer.mContainers.remove(tf3);
|
||||
taskContainer.removeTaskFragmentContainer(tf3);
|
||||
|
||||
assertWithMessage("Must return tf2 because tf2 has running activity.")
|
||||
.that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf2);
|
||||
|
||||
taskContainer.mContainers.remove(tf2);
|
||||
taskContainer.removeTaskFragmentContainer(tf2);
|
||||
|
||||
assertWithMessage("Must return tf because we are waiting for tf1 to appear.")
|
||||
.that(mSplitController.getTopActiveContainer(TASK_ID)).isEqualTo(tf1);
|
||||
@@ -365,7 +365,8 @@ public class SplitControllerTest {
|
||||
final Activity r1 = createMockActivity();
|
||||
addSplitTaskFragments(r0, r1);
|
||||
final TaskContainer taskContainer = mSplitController.getTaskContainer(TASK_ID);
|
||||
final TaskFragmentContainer taskFragmentContainer = taskContainer.mContainers.get(0);
|
||||
final TaskFragmentContainer taskFragmentContainer =
|
||||
taskContainer.getTaskFragmentContainers().get(0);
|
||||
spyOn(taskContainer);
|
||||
|
||||
// No update when the Task is invisible.
|
||||
@@ -1092,7 +1093,7 @@ public class SplitControllerTest {
|
||||
verify(mTransaction).finishActivity(mActivity.getActivityToken());
|
||||
verify(mTransaction).finishActivity(secondaryActivity0.getActivityToken());
|
||||
verify(mTransaction).finishActivity(secondaryActivity1.getActivityToken());
|
||||
assertTrue(taskContainer.mContainers.isEmpty());
|
||||
assertTrue(taskContainer.getTaskFragmentContainers().isEmpty());
|
||||
assertTrue(taskContainer.getSplitContainers().isEmpty());
|
||||
}
|
||||
|
||||
@@ -1365,15 +1366,13 @@ public class SplitControllerTest {
|
||||
TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID);
|
||||
tf.setInfo(mTransaction, createMockTaskFragmentInfo(tf, mActivity));
|
||||
|
||||
List<TaskFragmentContainer> containers = mSplitController.mTaskContainers.get(TASK_ID)
|
||||
.mContainers;
|
||||
|
||||
assertEquals(containers.get(0), tf);
|
||||
final TaskContainer taskContainer = mSplitController.mTaskContainers.get(TASK_ID);
|
||||
assertEquals(taskContainer.getTaskFragmentContainers().get(0), tf);
|
||||
|
||||
mSplitController.finishActivityStacks(Collections.singleton(tf.getTaskFragmentToken()));
|
||||
|
||||
verify(mSplitPresenter).deleteTaskFragment(any(), eq(tf.getTaskFragmentToken()));
|
||||
assertTrue(containers.isEmpty());
|
||||
assertTrue(taskContainer.getTaskFragmentContainers().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1383,10 +1382,8 @@ public class SplitControllerTest {
|
||||
bottomTf.setInfo(mTransaction, createMockTaskFragmentInfo(bottomTf, mActivity));
|
||||
topTf.setInfo(mTransaction, createMockTaskFragmentInfo(topTf, createMockActivity()));
|
||||
|
||||
List<TaskFragmentContainer> containers = mSplitController.mTaskContainers.get(TASK_ID)
|
||||
.mContainers;
|
||||
|
||||
assertEquals(containers.size(), 2);
|
||||
final TaskContainer taskContainer = mSplitController.mTaskContainers.get(TASK_ID);
|
||||
assertEquals(taskContainer.getTaskFragmentContainers().size(), 2);
|
||||
|
||||
Set<IBinder> activityStackTokens = new ArraySet<>(new IBinder[]{
|
||||
topTf.getTaskFragmentToken(), bottomTf.getTaskFragmentToken()});
|
||||
@@ -1405,7 +1402,7 @@ public class SplitControllerTest {
|
||||
+ "regardless of the order in ActivityStack set",
|
||||
topTf.getTaskFragmentToken(), fragmentTokens.get(1));
|
||||
|
||||
assertTrue(containers.isEmpty());
|
||||
assertTrue(taskContainer.getTaskFragmentContainers().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -127,7 +127,7 @@ public class TaskContainerTest {
|
||||
assertFalse(taskContainer.isEmpty());
|
||||
|
||||
taskContainer.mFinishedContainer.add(tf.getTaskFragmentToken());
|
||||
taskContainer.mContainers.clear();
|
||||
taskContainer.clearTaskFragmentContainer();
|
||||
|
||||
assertFalse(taskContainer.isEmpty());
|
||||
}
|
||||
@@ -152,13 +152,13 @@ public class TaskContainerTest {
|
||||
assertNull(taskContainer.getTopNonFinishingActivity());
|
||||
|
||||
final TaskFragmentContainer tf0 = mock(TaskFragmentContainer.class);
|
||||
taskContainer.mContainers.add(tf0);
|
||||
taskContainer.addTaskFragmentContainer(tf0);
|
||||
final Activity activity0 = mock(Activity.class);
|
||||
doReturn(activity0).when(tf0).getTopNonFinishingActivity();
|
||||
assertEquals(activity0, taskContainer.getTopNonFinishingActivity());
|
||||
|
||||
final TaskFragmentContainer tf1 = mock(TaskFragmentContainer.class);
|
||||
taskContainer.mContainers.add(tf1);
|
||||
taskContainer.addTaskFragmentContainer(tf1);
|
||||
assertEquals(activity0, taskContainer.getTopNonFinishingActivity());
|
||||
|
||||
final Activity activity1 = mock(Activity.class);
|
||||
|
||||
Reference in New Issue
Block a user