summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2022-05-26 19:06:54 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2022-05-26 19:06:54 +0000
commit3f75b0485accae00cb8b86b019c70502a623363a (patch)
tree0b4f84eb90b73ed1384ef233dabe2024d08680c6
parente00b1837906d1796e2e7310945bed2072e053dc6 (diff)
parentf7f106b4372b9b1a2254ae878aea91aaf55c7073 (diff)
Merge "Add pendingAppearedIntent to TaskFragmentContainer" into tm-dev
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java59
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java6
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java66
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java3
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java42
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java7
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java112
7 files changed, 227 insertions, 68 deletions
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 3380a23f3c09..575c3f002791 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -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);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index 43d0402c1525..ac3b05a0e825 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -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);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 26ddae4a0818..497c2478806e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -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();
}
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
index 792a53168a0d..a191e685f651 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
@@ -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);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 2fd491312f63..937d670287ad 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -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,11 +590,36 @@ 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();
setupSplitRule(primaryActivity, mActivity);
@@ -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());
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
index f1042ab6ce7d..ebe202db4e54 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
@@ -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());
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
index 587878f3bf01..fcbd8a3ac020 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
@@ -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.
@@ -113,10 +136,59 @@ public class TaskFragmentContainerTest {
}
@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 */);
+ }
}