Merge "Add pendingAppearedIntent to TaskFragmentContainer" into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
3f75b0485a
@@ -530,11 +530,18 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
|
||||
if (container == splitContainer.getPrimaryContainer()) {
|
||||
// The new launched can be in the primary container when it is starting a new activity
|
||||
// onCreate, thus the secondary may still be empty.
|
||||
// onCreate.
|
||||
final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
|
||||
final Intent secondaryIntent = secondaryContainer.getPendingAppearedIntent();
|
||||
if (secondaryIntent != null) {
|
||||
// Check with the pending Intent before it is started on the server side.
|
||||
// This can happen if the launched Activity start a new Intent to secondary during
|
||||
// #onCreated().
|
||||
return getSplitRule(launchedActivity, secondaryIntent) != null;
|
||||
}
|
||||
final Activity secondaryActivity = secondaryContainer.getTopNonFinishingActivity();
|
||||
return secondaryActivity == null
|
||||
|| getSplitRule(launchedActivity, secondaryActivity) != null;
|
||||
return secondaryActivity != null
|
||||
&& getSplitRule(launchedActivity, secondaryActivity) != null;
|
||||
}
|
||||
|
||||
// Check if the new launched activity is a placeholder.
|
||||
@@ -573,7 +580,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
Activity activityBelow = null;
|
||||
final TaskFragmentContainer container = getContainerWithActivity(activity);
|
||||
if (container != null) {
|
||||
final List<Activity> containerActivities = container.collectActivities();
|
||||
final List<Activity> containerActivities = container.collectNonFinishingActivities();
|
||||
final int index = containerActivities.indexOf(activity);
|
||||
if (index > 0) {
|
||||
activityBelow = containerActivities.get(index - 1);
|
||||
@@ -691,7 +698,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
|
||||
// 1. Whether the new activity intent should always expand.
|
||||
if (shouldExpand(null /* activity */, intent)) {
|
||||
return createEmptyExpandedContainer(wct, taskId, launchingActivity);
|
||||
return createEmptyExpandedContainer(wct, intent, taskId, launchingActivity);
|
||||
}
|
||||
|
||||
// 2. Whether the launching activity (if set) should be split with the new activity intent.
|
||||
@@ -742,7 +749,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
*/
|
||||
@Nullable
|
||||
private TaskFragmentContainer createEmptyExpandedContainer(
|
||||
@NonNull WindowContainerTransaction wct, int taskId,
|
||||
@NonNull WindowContainerTransaction wct, @NonNull Intent intent, int taskId,
|
||||
@Nullable Activity launchingActivity) {
|
||||
// We need an activity in the organizer process in the same Task to use as the owner
|
||||
// activity, as well as to get the Task window info.
|
||||
@@ -759,8 +766,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
// Can't find any activity in the Task that we can use as the owner activity.
|
||||
return null;
|
||||
}
|
||||
final TaskFragmentContainer expandedContainer = newContainer(null /* activity */,
|
||||
activityInTask, taskId);
|
||||
final TaskFragmentContainer expandedContainer = newContainer(intent, activityInTask,
|
||||
taskId);
|
||||
mPresenter.createTaskFragment(wct, expandedContainer.getTaskFragmentToken(),
|
||||
activityInTask.getActivityToken(), new Rect(), WINDOWING_MODE_UNDEFINED);
|
||||
return expandedContainer;
|
||||
@@ -789,7 +796,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
return splitContainer.getSecondaryContainer();
|
||||
}
|
||||
// Create a new TaskFragment to split with the primary activity for the new activity.
|
||||
return mPresenter.createNewSplitWithEmptySideContainer(wct, primaryActivity, splitRule);
|
||||
return mPresenter.createNewSplitWithEmptySideContainer(wct, primaryActivity, intent,
|
||||
splitRule);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -813,21 +821,34 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
return null;
|
||||
}
|
||||
|
||||
TaskFragmentContainer newContainer(@NonNull Activity activity, int taskId) {
|
||||
return newContainer(activity, activity, taskId);
|
||||
TaskFragmentContainer newContainer(@NonNull Activity pendingAppearedActivity, int taskId) {
|
||||
return newContainer(pendingAppearedActivity, pendingAppearedActivity, taskId);
|
||||
}
|
||||
|
||||
TaskFragmentContainer newContainer(@NonNull Activity pendingAppearedActivity,
|
||||
@NonNull Activity activityInTask, int taskId) {
|
||||
return newContainer(pendingAppearedActivity, null /* pendingAppearedIntent */,
|
||||
activityInTask, taskId);
|
||||
}
|
||||
|
||||
TaskFragmentContainer newContainer(@NonNull Intent pendingAppearedIntent,
|
||||
@NonNull Activity activityInTask, int taskId) {
|
||||
return newContainer(null /* pendingAppearedActivity */, pendingAppearedIntent,
|
||||
activityInTask, taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and registers a new organized container with an optional activity that will be
|
||||
* re-parented to it in a WCT.
|
||||
*
|
||||
* @param activity the activity that will be reparented to the TaskFragment.
|
||||
* @param activityInTask activity in the same Task so that we can get the Task bounds if
|
||||
* needed.
|
||||
* @param taskId parent Task of the new TaskFragment.
|
||||
* @param pendingAppearedActivity the activity that will be reparented to the TaskFragment.
|
||||
* @param pendingAppearedIntent the Intent that will be started in the TaskFragment.
|
||||
* @param activityInTask activity in the same Task so that we can get the Task bounds
|
||||
* if needed.
|
||||
* @param taskId parent Task of the new TaskFragment.
|
||||
*/
|
||||
TaskFragmentContainer newContainer(@Nullable Activity activity,
|
||||
@NonNull Activity activityInTask, int taskId) {
|
||||
TaskFragmentContainer newContainer(@Nullable Activity pendingAppearedActivity,
|
||||
@Nullable Intent pendingAppearedIntent, @NonNull Activity activityInTask, int taskId) {
|
||||
if (activityInTask == null) {
|
||||
throw new IllegalArgumentException("activityInTask must not be null,");
|
||||
}
|
||||
@@ -835,8 +856,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
||||
mTaskContainers.put(taskId, new TaskContainer(taskId));
|
||||
}
|
||||
final TaskContainer taskContainer = mTaskContainers.get(taskId);
|
||||
final TaskFragmentContainer container = new TaskFragmentContainer(activity, taskContainer,
|
||||
this);
|
||||
final TaskFragmentContainer container = new TaskFragmentContainer(pendingAppearedActivity,
|
||||
pendingAppearedIntent, taskContainer, this);
|
||||
if (!taskContainer.isTaskBoundsInitialized()) {
|
||||
// Get the initial bounds before the TaskFragment has appeared.
|
||||
final Rect taskBounds = SplitPresenter.getTaskBoundsFromActivity(activityInTask);
|
||||
|
||||
@@ -101,7 +101,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
|
||||
@NonNull
|
||||
TaskFragmentContainer createNewSplitWithEmptySideContainer(
|
||||
@NonNull WindowContainerTransaction wct, @NonNull Activity primaryActivity,
|
||||
@NonNull SplitPairRule rule) {
|
||||
@NonNull Intent secondaryIntent, @NonNull SplitPairRule rule) {
|
||||
final Rect parentBounds = getParentContainerBounds(primaryActivity);
|
||||
final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, parentBounds, rule,
|
||||
isLtr(primaryActivity, rule));
|
||||
@@ -111,7 +111,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
|
||||
// Create new empty task fragment
|
||||
final int taskId = primaryContainer.getTaskId();
|
||||
final TaskFragmentContainer secondaryContainer = mController.newContainer(
|
||||
null /* activity */, primaryActivity, taskId);
|
||||
secondaryIntent, primaryActivity, taskId);
|
||||
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds,
|
||||
rule, isLtr(primaryActivity, rule));
|
||||
final int windowingMode = mController.getTaskContainer(taskId)
|
||||
@@ -224,7 +224,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
|
||||
}
|
||||
|
||||
final int taskId = primaryContainer.getTaskId();
|
||||
TaskFragmentContainer secondaryContainer = mController.newContainer(null /* activity */,
|
||||
final TaskFragmentContainer secondaryContainer = mController.newContainer(activityIntent,
|
||||
launchingActivity, taskId);
|
||||
final int windowingMode = mController.getTaskContainer(taskId)
|
||||
.getWindowingModeForSplitTaskFragment(primaryRectBounds);
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Activity;
|
||||
import android.app.WindowConfiguration.WindowingMode;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
@@ -64,7 +65,16 @@ class TaskFragmentContainer {
|
||||
* Activities that are being reparented or being started to this container, but haven't been
|
||||
* added to {@link #mInfo} yet.
|
||||
*/
|
||||
private final ArrayList<Activity> mPendingAppearedActivities = new ArrayList<>();
|
||||
@VisibleForTesting
|
||||
final ArrayList<Activity> mPendingAppearedActivities = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* When this container is created for an {@link Intent} to start within, we store that Intent
|
||||
* until the container becomes non-empty on the server side, so that we can use it to check
|
||||
* rules associated with this container.
|
||||
*/
|
||||
@Nullable
|
||||
private Intent mPendingAppearedIntent;
|
||||
|
||||
/** Containers that are dependent on this one and should be completely destroyed on exit. */
|
||||
private final List<TaskFragmentContainer> mContainersToFinishOnExit =
|
||||
@@ -99,15 +109,22 @@ class TaskFragmentContainer {
|
||||
* Creates a container with an existing activity that will be re-parented to it in a window
|
||||
* container transaction.
|
||||
*/
|
||||
TaskFragmentContainer(@Nullable Activity activity, @NonNull TaskContainer taskContainer,
|
||||
TaskFragmentContainer(@Nullable Activity pendingAppearedActivity,
|
||||
@Nullable Intent pendingAppearedIntent, @NonNull TaskContainer taskContainer,
|
||||
@NonNull SplitController controller) {
|
||||
if ((pendingAppearedActivity == null && pendingAppearedIntent == null)
|
||||
|| (pendingAppearedActivity != null && pendingAppearedIntent != null)) {
|
||||
throw new IllegalArgumentException(
|
||||
"One and only one of pending activity and intent must be non-null");
|
||||
}
|
||||
mController = controller;
|
||||
mToken = new Binder("TaskFragmentContainer");
|
||||
mTaskContainer = taskContainer;
|
||||
taskContainer.mContainers.add(this);
|
||||
if (activity != null) {
|
||||
addPendingAppearedActivity(activity);
|
||||
if (pendingAppearedActivity != null) {
|
||||
addPendingAppearedActivity(pendingAppearedActivity);
|
||||
}
|
||||
mPendingAppearedIntent = pendingAppearedIntent;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,9 +135,9 @@ class TaskFragmentContainer {
|
||||
return mToken;
|
||||
}
|
||||
|
||||
/** List of activities that belong to this container and live in this process. */
|
||||
/** List of non-finishing activities that belong to this container and live in this process. */
|
||||
@NonNull
|
||||
List<Activity> collectActivities() {
|
||||
List<Activity> collectNonFinishingActivities() {
|
||||
final List<Activity> allActivities = new ArrayList<>();
|
||||
if (mInfo != null) {
|
||||
// Add activities reported from the server.
|
||||
@@ -154,13 +171,14 @@ class TaskFragmentContainer {
|
||||
return false;
|
||||
}
|
||||
return mPendingAppearedActivities.isEmpty()
|
||||
&& mInfo.getActivities().size() == collectActivities().size();
|
||||
&& mInfo.getActivities().size() == collectNonFinishingActivities().size();
|
||||
}
|
||||
|
||||
ActivityStack toActivityStack() {
|
||||
return new ActivityStack(collectActivities(), isEmpty());
|
||||
return new ActivityStack(collectNonFinishingActivities(), isEmpty());
|
||||
}
|
||||
|
||||
/** Adds the activity that will be reparented to this container. */
|
||||
void addPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
|
||||
if (hasActivity(pendingAppearedActivity.getActivityToken())) {
|
||||
return;
|
||||
@@ -174,6 +192,11 @@ class TaskFragmentContainer {
|
||||
mPendingAppearedActivities.remove(pendingAppearedActivity);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Intent getPendingAppearedIntent() {
|
||||
return mPendingAppearedIntent;
|
||||
}
|
||||
|
||||
boolean hasActivity(@NonNull IBinder token) {
|
||||
if (mInfo != null && mInfo.getActivities().contains(token)) {
|
||||
return true;
|
||||
@@ -219,7 +242,12 @@ class TaskFragmentContainer {
|
||||
}
|
||||
|
||||
mInfo = info;
|
||||
if (mInfo == null || mPendingAppearedActivities.isEmpty()) {
|
||||
if (mInfo == null || mInfo.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// Only track the pending Intent when the container is empty.
|
||||
mPendingAppearedIntent = null;
|
||||
if (mPendingAppearedActivities.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// Cleanup activities that were being re-parented
|
||||
@@ -234,20 +262,13 @@ class TaskFragmentContainer {
|
||||
|
||||
@Nullable
|
||||
Activity getTopNonFinishingActivity() {
|
||||
List<Activity> activities = collectActivities();
|
||||
if (activities.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
int i = activities.size() - 1;
|
||||
while (i >= 0 && activities.get(i).isFinishing()) {
|
||||
i--;
|
||||
}
|
||||
return i >= 0 ? activities.get(i) : null;
|
||||
final List<Activity> activities = collectNonFinishingActivities();
|
||||
return activities.isEmpty() ? null : activities.get(activities.size() - 1);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Activity getBottomMostActivity() {
|
||||
final List<Activity> activities = collectActivities();
|
||||
final List<Activity> activities = collectNonFinishingActivities();
|
||||
return activities.isEmpty() ? null : activities.get(0);
|
||||
}
|
||||
|
||||
@@ -320,8 +341,11 @@ class TaskFragmentContainer {
|
||||
private void finishActivities(boolean shouldFinishDependent, @NonNull SplitPresenter presenter,
|
||||
@NonNull WindowContainerTransaction wct, @NonNull SplitController controller) {
|
||||
// Finish own activities
|
||||
for (Activity activity : collectActivities()) {
|
||||
if (!activity.isFinishing()) {
|
||||
for (Activity activity : collectNonFinishingActivities()) {
|
||||
if (!activity.isFinishing()
|
||||
// In case we have requested to reparent the activity to another container (as
|
||||
// pendingAppeared), we don't want to finish it with this container.
|
||||
&& mController.getContainerWithActivity(activity) == this) {
|
||||
activity.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Point;
|
||||
import android.os.Handler;
|
||||
@@ -115,7 +116,7 @@ public class JetpackTaskFragmentOrganizerTest {
|
||||
public void testExpandTaskFragment() {
|
||||
final TaskContainer taskContainer = new TaskContainer(TASK_ID);
|
||||
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
|
||||
taskContainer, mSplitController);
|
||||
new Intent(), taskContainer, mSplitController);
|
||||
final TaskFragmentInfo info = createMockInfo(container);
|
||||
mOrganizer.mFragmentInfos.put(container.getTaskFragmentToken(), info);
|
||||
container.setInfo(info);
|
||||
|
||||
@@ -123,7 +123,7 @@ public class SplitControllerTest {
|
||||
final TaskContainer taskContainer = new TaskContainer(TASK_ID);
|
||||
// tf1 has no running activity so is not active.
|
||||
final TaskFragmentContainer tf1 = new TaskFragmentContainer(null /* activity */,
|
||||
taskContainer, mSplitController);
|
||||
new Intent(), taskContainer, mSplitController);
|
||||
// tf2 has running activity so is active.
|
||||
final TaskFragmentContainer tf2 = mock(TaskFragmentContainer.class);
|
||||
doReturn(1).when(tf2).getRunningActivityCount();
|
||||
@@ -205,7 +205,8 @@ public class SplitControllerTest {
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
mSplitController.newContainer(mActivity, null /* launchingActivity */, TASK_ID));
|
||||
|
||||
final TaskFragmentContainer tf = mSplitController.newContainer(null, mActivity, TASK_ID);
|
||||
final TaskFragmentContainer tf = mSplitController.newContainer(mActivity, mActivity,
|
||||
TASK_ID);
|
||||
final TaskContainer taskContainer = mSplitController.getTaskContainer(TASK_ID);
|
||||
|
||||
assertNotNull(tf);
|
||||
@@ -307,7 +308,7 @@ public class SplitControllerTest {
|
||||
@Test
|
||||
public void testOnActivityReparentToTask_diffProcess() {
|
||||
// Create an empty TaskFragment to initialize for the Task.
|
||||
mSplitController.newContainer(null, mActivity, TASK_ID);
|
||||
mSplitController.newContainer(new Intent(), mActivity, TASK_ID);
|
||||
final IBinder activityToken = new Binder();
|
||||
final Intent intent = new Intent();
|
||||
|
||||
@@ -417,7 +418,7 @@ public class SplitControllerTest {
|
||||
|
||||
verify(mSplitPresenter, never()).applyTransaction(any());
|
||||
|
||||
mSplitController.newContainer(null /* activity */, mActivity, TASK_ID);
|
||||
mSplitController.newContainer(new Intent(), mActivity, TASK_ID);
|
||||
mSplitController.placeActivityInTopContainer(mActivity);
|
||||
|
||||
verify(mSplitPresenter).applyTransaction(any());
|
||||
@@ -436,7 +437,7 @@ public class SplitControllerTest {
|
||||
false /* isOnReparent */);
|
||||
|
||||
assertFalse(result);
|
||||
verify(mSplitController, never()).newContainer(any(), any(), anyInt());
|
||||
verify(mSplitController, never()).newContainer(any(), any(), any(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -577,7 +578,7 @@ public class SplitControllerTest {
|
||||
final TaskFragmentContainer primaryContainer = mSplitController.newContainer(mActivity,
|
||||
TASK_ID);
|
||||
final TaskFragmentContainer secondaryContainer = mSplitController.newContainer(
|
||||
null /* activity */, mActivity, TASK_ID);
|
||||
secondaryIntent, mActivity, TASK_ID);
|
||||
mSplitController.registerSplit(
|
||||
mTransaction,
|
||||
primaryContainer,
|
||||
@@ -589,10 +590,35 @@ public class SplitControllerTest {
|
||||
false /* isOnReparent */);
|
||||
|
||||
assertTrue(result);
|
||||
verify(mSplitController, never()).newContainer(any(), any(), anyInt());
|
||||
verify(mSplitController, never()).newContainer(any(), any(), any(), anyInt());
|
||||
verify(mSplitController, never()).registerSplit(any(), any(), any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveActivityToContainer_splitRule_inPrimarySplitWithNoRuleMatched() {
|
||||
final Intent secondaryIntent = new Intent();
|
||||
setupSplitRule(mActivity, secondaryIntent);
|
||||
final SplitPairRule splitRule = (SplitPairRule) mSplitController.getSplitRules().get(0);
|
||||
|
||||
// The new launched activity is in primary split, but there is no rule for it to split with
|
||||
// the secondary, so return false.
|
||||
final TaskFragmentContainer primaryContainer = mSplitController.newContainer(mActivity,
|
||||
TASK_ID);
|
||||
final TaskFragmentContainer secondaryContainer = mSplitController.newContainer(
|
||||
secondaryIntent, mActivity, TASK_ID);
|
||||
mSplitController.registerSplit(
|
||||
mTransaction,
|
||||
primaryContainer,
|
||||
mActivity,
|
||||
secondaryContainer,
|
||||
splitRule);
|
||||
final Activity launchedActivity = createMockActivity();
|
||||
primaryContainer.addPendingAppearedActivity(launchedActivity);
|
||||
|
||||
assertFalse(mSplitController.resolveActivityToContainer(launchedActivity,
|
||||
false /* isOnReparent */));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveActivityToContainer_splitRule_inSecondarySplitWithRuleMatched() {
|
||||
final Activity primaryActivity = createMockActivity();
|
||||
@@ -605,7 +631,7 @@ public class SplitControllerTest {
|
||||
false /* isOnReparent */);
|
||||
|
||||
assertTrue(result);
|
||||
verify(mSplitController, never()).newContainer(any(), any(), anyInt());
|
||||
verify(mSplitController, never()).newContainer(any(), any(), any(), anyInt());
|
||||
verify(mSplitController, never()).registerSplit(any(), any(), any(), any(), any());
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Rect;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
@@ -142,7 +143,7 @@ public class TaskContainerTest {
|
||||
assertTrue(taskContainer.isEmpty());
|
||||
|
||||
final TaskFragmentContainer tf = new TaskFragmentContainer(null /* activity */,
|
||||
taskContainer, mController);
|
||||
new Intent(), taskContainer, mController);
|
||||
|
||||
assertFalse(taskContainer.isEmpty());
|
||||
|
||||
@@ -158,11 +159,11 @@ public class TaskContainerTest {
|
||||
assertNull(taskContainer.getTopTaskFragmentContainer());
|
||||
|
||||
final TaskFragmentContainer tf0 = new TaskFragmentContainer(null /* activity */,
|
||||
taskContainer, mController);
|
||||
new Intent(), taskContainer, mController);
|
||||
assertEquals(tf0, taskContainer.getTopTaskFragmentContainer());
|
||||
|
||||
final TaskFragmentContainer tf1 = new TaskFragmentContainer(null /* activity */,
|
||||
taskContainer, mController);
|
||||
new Intent(), taskContainer, mController);
|
||||
assertEquals(tf1, taskContainer.getTopTaskFragmentContainer());
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
@@ -29,12 +30,17 @@ import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Point;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.window.TaskFragmentInfo;
|
||||
import android.window.WindowContainerToken;
|
||||
import android.window.WindowContainerTransaction;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
@@ -49,6 +55,7 @@ import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -72,19 +79,35 @@ public class TaskFragmentContainerTest {
|
||||
@Mock
|
||||
private Handler mHandler;
|
||||
private Activity mActivity;
|
||||
private Intent mIntent;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
doReturn(mHandler).when(mController).getHandler();
|
||||
mActivity = createMockActivity();
|
||||
mIntent = new Intent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewContainer() {
|
||||
final TaskContainer taskContainer = new TaskContainer(TASK_ID);
|
||||
|
||||
// One of the activity and the intent must be non-null
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> new TaskFragmentContainer(null, null, taskContainer, mController));
|
||||
|
||||
// One of the activity and the intent must be null.
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> new TaskFragmentContainer(mActivity, mIntent, taskContainer, mController));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFinish() {
|
||||
final TaskContainer taskContainer = new TaskContainer(TASK_ID);
|
||||
final TaskFragmentContainer container = new TaskFragmentContainer(mActivity, taskContainer,
|
||||
mController);
|
||||
final TaskFragmentContainer container = new TaskFragmentContainer(mActivity,
|
||||
null /* pendingAppearedIntent */, taskContainer, mController);
|
||||
doReturn(container).when(mController).getContainerWithActivity(mActivity);
|
||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
|
||||
// Only remove the activity, but not clear the reference until appeared.
|
||||
@@ -112,11 +135,60 @@ public class TaskFragmentContainerTest {
|
||||
verify(mController).removeContainer(container);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFinish_notFinishActivityThatIsReparenting() {
|
||||
final TaskContainer taskContainer = new TaskContainer(TASK_ID);
|
||||
final TaskFragmentContainer container0 = new TaskFragmentContainer(mActivity,
|
||||
null /* pendingAppearedIntent */, taskContainer, mController);
|
||||
final TaskFragmentInfo info = createMockTaskFragmentInfo(container0, mActivity);
|
||||
container0.setInfo(info);
|
||||
// Request to reparent the activity to a new TaskFragment.
|
||||
final TaskFragmentContainer container1 = new TaskFragmentContainer(mActivity,
|
||||
null /* pendingAppearedIntent */, taskContainer, mController);
|
||||
doReturn(container1).when(mController).getContainerWithActivity(mActivity);
|
||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
|
||||
// The activity is requested to be reparented, so don't finish it.
|
||||
container0.finish(true /* shouldFinishDependent */, mPresenter, wct, mController);
|
||||
|
||||
verify(mActivity, never()).finish();
|
||||
verify(mPresenter).deleteTaskFragment(wct, container0.getTaskFragmentToken());
|
||||
verify(mController).removeContainer(container0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetInfo() {
|
||||
final TaskContainer taskContainer = new TaskContainer(TASK_ID);
|
||||
// Pending activity should be cleared when it has appeared on server side.
|
||||
final TaskFragmentContainer pendingActivityContainer = new TaskFragmentContainer(mActivity,
|
||||
null /* pendingAppearedIntent */, taskContainer, mController);
|
||||
|
||||
assertTrue(pendingActivityContainer.mPendingAppearedActivities.contains(mActivity));
|
||||
|
||||
final TaskFragmentInfo info0 = createMockTaskFragmentInfo(pendingActivityContainer,
|
||||
mActivity);
|
||||
pendingActivityContainer.setInfo(info0);
|
||||
|
||||
assertTrue(pendingActivityContainer.mPendingAppearedActivities.isEmpty());
|
||||
|
||||
// Pending intent should be cleared when the container becomes non-empty.
|
||||
final TaskFragmentContainer pendingIntentContainer = new TaskFragmentContainer(
|
||||
null /* pendingAppearedActivity */, mIntent, taskContainer, mController);
|
||||
|
||||
assertEquals(mIntent, pendingIntentContainer.getPendingAppearedIntent());
|
||||
|
||||
final TaskFragmentInfo info1 = createMockTaskFragmentInfo(pendingIntentContainer,
|
||||
mActivity);
|
||||
pendingIntentContainer.setInfo(info1);
|
||||
|
||||
assertNull(pendingIntentContainer.getPendingAppearedIntent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsWaitingActivityAppear() {
|
||||
final TaskContainer taskContainer = new TaskContainer(TASK_ID);
|
||||
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
|
||||
taskContainer, mController);
|
||||
mIntent, taskContainer, mController);
|
||||
|
||||
assertTrue(container.isWaitingActivityAppear());
|
||||
|
||||
@@ -137,7 +209,7 @@ public class TaskFragmentContainerTest {
|
||||
public void testAppearEmptyTimeout() {
|
||||
final TaskContainer taskContainer = new TaskContainer(TASK_ID);
|
||||
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
|
||||
taskContainer, mController);
|
||||
mIntent, taskContainer, mController);
|
||||
|
||||
assertNull(container.mAppearEmptyTimeout);
|
||||
|
||||
@@ -173,16 +245,16 @@ public class TaskFragmentContainerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCollectActivities() {
|
||||
public void testCollectNonFinishingActivities() {
|
||||
final TaskContainer taskContainer = new TaskContainer(TASK_ID);
|
||||
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
|
||||
taskContainer, mController);
|
||||
List<Activity> activities = container.collectActivities();
|
||||
mIntent, taskContainer, mController);
|
||||
List<Activity> activities = container.collectNonFinishingActivities();
|
||||
|
||||
assertTrue(activities.isEmpty());
|
||||
|
||||
container.addPendingAppearedActivity(mActivity);
|
||||
activities = container.collectActivities();
|
||||
activities = container.collectNonFinishingActivities();
|
||||
|
||||
assertEquals(1, activities.size());
|
||||
|
||||
@@ -192,7 +264,7 @@ public class TaskFragmentContainerTest {
|
||||
activity1.getActivityToken());
|
||||
doReturn(runningActivities).when(mInfo).getActivities();
|
||||
container.setInfo(mInfo);
|
||||
activities = container.collectActivities();
|
||||
activities = container.collectNonFinishingActivities();
|
||||
|
||||
assertEquals(3, activities.size());
|
||||
assertEquals(activity0, activities.get(0));
|
||||
@@ -204,21 +276,21 @@ public class TaskFragmentContainerTest {
|
||||
public void testAddPendingActivity() {
|
||||
final TaskContainer taskContainer = new TaskContainer(TASK_ID);
|
||||
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
|
||||
taskContainer, mController);
|
||||
mIntent, taskContainer, mController);
|
||||
container.addPendingAppearedActivity(mActivity);
|
||||
|
||||
assertEquals(1, container.collectActivities().size());
|
||||
assertEquals(1, container.collectNonFinishingActivities().size());
|
||||
|
||||
container.addPendingAppearedActivity(mActivity);
|
||||
|
||||
assertEquals(1, container.collectActivities().size());
|
||||
assertEquals(1, container.collectNonFinishingActivities().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBottomMostActivity() {
|
||||
final TaskContainer taskContainer = new TaskContainer(TASK_ID);
|
||||
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
|
||||
taskContainer, mController);
|
||||
mIntent, taskContainer, mController);
|
||||
container.addPendingAppearedActivity(mActivity);
|
||||
|
||||
assertEquals(mActivity, container.getBottomMostActivity());
|
||||
@@ -239,4 +311,18 @@ public class TaskFragmentContainerTest {
|
||||
doReturn(activity).when(mController).getActivity(activityToken);
|
||||
return activity;
|
||||
}
|
||||
|
||||
/** Creates a mock TaskFragmentInfo for the given TaskFragment. */
|
||||
private TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container,
|
||||
@NonNull Activity activity) {
|
||||
return new TaskFragmentInfo(container.getTaskFragmentToken(),
|
||||
mock(WindowContainerToken.class),
|
||||
new Configuration(),
|
||||
1,
|
||||
true /* isVisible */,
|
||||
Collections.singletonList(activity.getActivityToken()),
|
||||
new Point(),
|
||||
false /* isTaskClearedForReuse */,
|
||||
false /* isTaskFragmentClearedForPip */);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user