Merge "Fix activity relaunch issue with ActivityEmbedding" into tm-qpr-dev
This commit is contained in:
@@ -965,10 +965,16 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
void onActivityDestroyed(@NonNull Activity activity) {
|
void onActivityDestroyed(@NonNull Activity activity) {
|
||||||
|
if (!activity.isFinishing()) {
|
||||||
|
// onDestroyed is triggered without finishing. This happens when the activity is
|
||||||
|
// relaunched. In this case, we don't want to cleanup the record.
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Remove any pending appeared activity, as the server won't send finished activity to the
|
// Remove any pending appeared activity, as the server won't send finished activity to the
|
||||||
// organizer.
|
// organizer.
|
||||||
|
final IBinder activityToken = activity.getActivityToken();
|
||||||
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
|
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
|
||||||
mTaskContainers.valueAt(i).onActivityDestroyed(activity);
|
mTaskContainers.valueAt(i).onActivityDestroyed(activityToken);
|
||||||
}
|
}
|
||||||
// We didn't trigger the callback if there were any pending appeared activities, so check
|
// We didn't trigger the callback if there were any pending appeared activities, so check
|
||||||
// again after the pending is removed.
|
// again after the pending is removed.
|
||||||
@@ -1170,16 +1176,33 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
* Returns a container that this activity is registered with. An activity can only belong to one
|
* Returns a container that this activity is registered with. An activity can only belong to one
|
||||||
* container, or no container at all.
|
* container, or no container at all.
|
||||||
*/
|
*/
|
||||||
|
@GuardedBy("mLock")
|
||||||
@Nullable
|
@Nullable
|
||||||
TaskFragmentContainer getContainerWithActivity(@NonNull Activity activity) {
|
TaskFragmentContainer getContainerWithActivity(@NonNull Activity activity) {
|
||||||
final IBinder activityToken = activity.getActivityToken();
|
return getContainerWithActivity(activity.getActivityToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
@Nullable
|
||||||
|
TaskFragmentContainer getContainerWithActivity(@NonNull IBinder activityToken) {
|
||||||
|
// Check pending appeared activity first because there can be a delay for the server
|
||||||
|
// update.
|
||||||
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
|
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
|
||||||
final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
|
final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
|
||||||
// Traverse from top to bottom in case an activity is added to top pending, and hasn't
|
|
||||||
// received update from server yet.
|
|
||||||
for (int j = containers.size() - 1; j >= 0; j--) {
|
for (int j = containers.size() - 1; j >= 0; j--) {
|
||||||
final TaskFragmentContainer container = containers.get(j);
|
final TaskFragmentContainer container = containers.get(j);
|
||||||
if (container.hasActivity(activityToken)) {
|
if (container.hasPendingAppearedActivity(activityToken)) {
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
for (int j = containers.size() - 1; j >= 0; j--) {
|
||||||
|
final TaskFragmentContainer container = containers.get(j);
|
||||||
|
if (container.hasAppearedActivity(activityToken)) {
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,16 +166,16 @@ class TaskContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Called when the activity is destroyed. */
|
/** Called when the activity is destroyed. */
|
||||||
void onActivityDestroyed(@NonNull Activity activity) {
|
void onActivityDestroyed(@NonNull IBinder activityToken) {
|
||||||
for (TaskFragmentContainer container : mContainers) {
|
for (TaskFragmentContainer container : mContainers) {
|
||||||
container.onActivityDestroyed(activity);
|
container.onActivityDestroyed(activityToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Removes the pending appeared activity from all TaskFragments in this Task. */
|
/** Removes the pending appeared activity from all TaskFragments in this Task. */
|
||||||
void cleanupPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
|
void cleanupPendingAppearedActivity(@NonNull IBinder activityToken) {
|
||||||
for (TaskFragmentContainer container : mContainers) {
|
for (TaskFragmentContainer container : mContainers) {
|
||||||
container.removePendingAppearedActivity(pendingAppearedActivity);
|
container.removePendingAppearedActivity(activityToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ import java.util.List;
|
|||||||
* Client-side container for a stack of activities. Corresponds to an instance of TaskFragment
|
* Client-side container for a stack of activities. Corresponds to an instance of TaskFragment
|
||||||
* on the server side.
|
* on the server side.
|
||||||
*/
|
*/
|
||||||
|
// Suppress GuardedBy warning because all the TaskFragmentContainers are stored in
|
||||||
|
// SplitController.mTaskContainers which is guarded.
|
||||||
|
@SuppressWarnings("GuardedBy")
|
||||||
class TaskFragmentContainer {
|
class TaskFragmentContainer {
|
||||||
private static final int APPEAR_EMPTY_TIMEOUT_MS = 3000;
|
private static final int APPEAR_EMPTY_TIMEOUT_MS = 3000;
|
||||||
|
|
||||||
@@ -66,11 +69,11 @@ class TaskFragmentContainer {
|
|||||||
TaskFragmentInfo mInfo;
|
TaskFragmentInfo mInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activities that are being reparented or being started to this container, but haven't been
|
* Activity tokens that are being reparented or being started to this container, but haven't
|
||||||
* added to {@link #mInfo} yet.
|
* been added to {@link #mInfo} yet.
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
final ArrayList<Activity> mPendingAppearedActivities = new ArrayList<>();
|
final ArrayList<IBinder> mPendingAppearedActivities = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When this container is created for an {@link Intent} to start within, we store that Intent
|
* When this container is created for an {@link Intent} to start within, we store that Intent
|
||||||
@@ -84,8 +87,11 @@ class TaskFragmentContainer {
|
|||||||
private final List<TaskFragmentContainer> mContainersToFinishOnExit =
|
private final List<TaskFragmentContainer> mContainersToFinishOnExit =
|
||||||
new ArrayList<>();
|
new ArrayList<>();
|
||||||
|
|
||||||
/** Individual associated activities in different containers that should be finished on exit. */
|
/**
|
||||||
private final List<Activity> mActivitiesToFinishOnExit = new ArrayList<>();
|
* Individual associated activity tokens in different containers that should be finished on
|
||||||
|
* exit.
|
||||||
|
*/
|
||||||
|
private final List<IBinder> mActivitiesToFinishOnExit = new ArrayList<>();
|
||||||
|
|
||||||
/** Indicates whether the container was cleaned up after the last activity was removed. */
|
/** Indicates whether the container was cleaned up after the last activity was removed. */
|
||||||
private boolean mIsFinished;
|
private boolean mIsFinished;
|
||||||
@@ -158,8 +164,9 @@ class TaskFragmentContainer {
|
|||||||
// in this intermediate state.
|
// in this intermediate state.
|
||||||
// Place those on top of the list since they will be on the top after reported from the
|
// Place those on top of the list since they will be on the top after reported from the
|
||||||
// server.
|
// server.
|
||||||
for (Activity activity : mPendingAppearedActivities) {
|
for (IBinder token : mPendingAppearedActivities) {
|
||||||
if (!activity.isFinishing()) {
|
final Activity activity = mController.getActivity(token);
|
||||||
|
if (activity != null && !activity.isFinishing()) {
|
||||||
allActivities.add(activity);
|
allActivities.add(activity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,55 +210,58 @@ class TaskFragmentContainer {
|
|||||||
|
|
||||||
/** Adds the activity that will be reparented to this container. */
|
/** Adds the activity that will be reparented to this container. */
|
||||||
void addPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
|
void addPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
|
||||||
if (hasActivity(pendingAppearedActivity.getActivityToken())) {
|
final IBinder activityToken = pendingAppearedActivity.getActivityToken();
|
||||||
|
if (hasActivity(activityToken)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Remove the pending activity from other TaskFragments.
|
// Remove the pending activity from other TaskFragments in case the activity is reparented
|
||||||
mTaskContainer.cleanupPendingAppearedActivity(pendingAppearedActivity);
|
// again before the server update.
|
||||||
mPendingAppearedActivities.add(pendingAppearedActivity);
|
mTaskContainer.cleanupPendingAppearedActivity(activityToken);
|
||||||
updateActivityClientRecordTaskFragmentToken(pendingAppearedActivity);
|
mPendingAppearedActivities.add(activityToken);
|
||||||
|
updateActivityClientRecordTaskFragmentToken(activityToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the {@link ActivityThread.ActivityClientRecord#mTaskFragmentToken} for the
|
* Updates the {@link ActivityThread.ActivityClientRecord#mTaskFragmentToken} for the
|
||||||
* activity. This makes sure the token is up-to-date if the activity is relaunched later.
|
* activity. This makes sure the token is up-to-date if the activity is relaunched later.
|
||||||
*/
|
*/
|
||||||
private void updateActivityClientRecordTaskFragmentToken(@NonNull Activity activity) {
|
private void updateActivityClientRecordTaskFragmentToken(@NonNull IBinder activityToken) {
|
||||||
final ActivityThread.ActivityClientRecord record = ActivityThread
|
final ActivityThread.ActivityClientRecord record = ActivityThread
|
||||||
.currentActivityThread().getActivityClient(activity.getActivityToken());
|
.currentActivityThread().getActivityClient(activityToken);
|
||||||
if (record != null) {
|
if (record != null) {
|
||||||
record.mTaskFragmentToken = mToken;
|
record.mTaskFragmentToken = mToken;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void removePendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
|
void removePendingAppearedActivity(@NonNull IBinder activityToken) {
|
||||||
mPendingAppearedActivities.remove(pendingAppearedActivity);
|
mPendingAppearedActivities.remove(activityToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearPendingAppearedActivities() {
|
void clearPendingAppearedActivities() {
|
||||||
final List<Activity> cleanupActivities = new ArrayList<>(mPendingAppearedActivities);
|
final List<IBinder> cleanupActivities = new ArrayList<>(mPendingAppearedActivities);
|
||||||
// Clear mPendingAppearedActivities so that #getContainerWithActivity won't return the
|
// Clear mPendingAppearedActivities so that #getContainerWithActivity won't return the
|
||||||
// current TaskFragment.
|
// current TaskFragment.
|
||||||
mPendingAppearedActivities.clear();
|
mPendingAppearedActivities.clear();
|
||||||
mPendingAppearedIntent = null;
|
mPendingAppearedIntent = null;
|
||||||
|
|
||||||
// For removed pending activities, we need to update the them to their previous containers.
|
// For removed pending activities, we need to update the them to their previous containers.
|
||||||
for (Activity activity : cleanupActivities) {
|
for (IBinder activityToken : cleanupActivities) {
|
||||||
final TaskFragmentContainer curContainer = mController.getContainerWithActivity(
|
final TaskFragmentContainer curContainer = mController.getContainerWithActivity(
|
||||||
activity);
|
activityToken);
|
||||||
if (curContainer != null) {
|
if (curContainer != null) {
|
||||||
curContainer.updateActivityClientRecordTaskFragmentToken(activity);
|
curContainer.updateActivityClientRecordTaskFragmentToken(activityToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when the activity is destroyed. */
|
/** Called when the activity is destroyed. */
|
||||||
void onActivityDestroyed(@NonNull Activity activity) {
|
void onActivityDestroyed(@NonNull IBinder activityToken) {
|
||||||
removePendingAppearedActivity(activity);
|
removePendingAppearedActivity(activityToken);
|
||||||
if (mInfo != null) {
|
if (mInfo != null) {
|
||||||
// Remove the activity now because there can be a delay before the server callback.
|
// Remove the activity now because there can be a delay before the server callback.
|
||||||
mInfo.getActivities().remove(activity.getActivityToken());
|
mInfo.getActivities().remove(activityToken);
|
||||||
}
|
}
|
||||||
|
mActivitiesToFinishOnExit.remove(activityToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -275,16 +285,24 @@ class TaskFragmentContainer {
|
|||||||
mPendingAppearedIntent = null;
|
mPendingAppearedIntent = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hasActivity(@NonNull IBinder token) {
|
boolean hasActivity(@NonNull IBinder activityToken) {
|
||||||
if (mInfo != null && mInfo.getActivities().contains(token)) {
|
// Instead of using (hasAppearedActivity() || hasPendingAppearedActivity), we want to make
|
||||||
return true;
|
// sure the controller considers this container as the one containing the activity.
|
||||||
}
|
// This is needed when the activity is added as pending appeared activity to one
|
||||||
for (Activity activity : mPendingAppearedActivities) {
|
// TaskFragment while it is also an appeared activity in another.
|
||||||
if (activity.getActivityToken().equals(token)) {
|
return mController.getContainerWithActivity(activityToken) == this;
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
}
|
/** Whether this activity has appeared in the TaskFragment on the server side. */
|
||||||
return false;
|
boolean hasAppearedActivity(@NonNull IBinder activityToken) {
|
||||||
|
return mInfo != null && mInfo.getActivities().contains(activityToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether we are waiting for this activity to appear in the TaskFragment on the server side.
|
||||||
|
*/
|
||||||
|
boolean hasPendingAppearedActivity(@NonNull IBinder activityToken) {
|
||||||
|
return mPendingAppearedActivities.contains(activityToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getRunningActivityCount() {
|
int getRunningActivityCount() {
|
||||||
@@ -342,8 +360,8 @@ class TaskFragmentContainer {
|
|||||||
// Cleanup activities that were being re-parented
|
// Cleanup activities that were being re-parented
|
||||||
List<IBinder> infoActivities = mInfo.getActivities();
|
List<IBinder> infoActivities = mInfo.getActivities();
|
||||||
for (int i = mPendingAppearedActivities.size() - 1; i >= 0; --i) {
|
for (int i = mPendingAppearedActivities.size() - 1; i >= 0; --i) {
|
||||||
final Activity activity = mPendingAppearedActivities.get(i);
|
final IBinder activityToken = mPendingAppearedActivities.get(i);
|
||||||
if (infoActivities.contains(activity.getActivityToken())) {
|
if (infoActivities.contains(activityToken)) {
|
||||||
mPendingAppearedActivities.remove(i);
|
mPendingAppearedActivities.remove(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -392,7 +410,7 @@ class TaskFragmentContainer {
|
|||||||
if (mIsFinished) {
|
if (mIsFinished) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mActivitiesToFinishOnExit.add(activityToFinish);
|
mActivitiesToFinishOnExit.add(activityToFinish.getActivityToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -402,7 +420,7 @@ class TaskFragmentContainer {
|
|||||||
if (mIsFinished) {
|
if (mIsFinished) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mActivitiesToFinishOnExit.remove(activityToRemove);
|
mActivitiesToFinishOnExit.remove(activityToRemove.getActivityToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Removes all dependencies that should be finished when this container is finished. */
|
/** Removes all dependencies that should be finished when this container is finished. */
|
||||||
@@ -470,8 +488,9 @@ class TaskFragmentContainer {
|
|||||||
mContainersToFinishOnExit.clear();
|
mContainersToFinishOnExit.clear();
|
||||||
|
|
||||||
// Finish associated activities
|
// Finish associated activities
|
||||||
for (Activity activity : mActivitiesToFinishOnExit) {
|
for (IBinder activityToken : mActivitiesToFinishOnExit) {
|
||||||
if (activity.isFinishing()
|
final Activity activity = mController.getActivity(activityToken);
|
||||||
|
if (activity == null || activity.isFinishing()
|
||||||
|| controller.shouldRetainAssociatedActivity(this, activity)) {
|
|| controller.shouldRetainAssociatedActivity(this, activity)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -540,7 +559,8 @@ class TaskFragmentContainer {
|
|||||||
}
|
}
|
||||||
int maxMinWidth = mInfo.getMinimumWidth();
|
int maxMinWidth = mInfo.getMinimumWidth();
|
||||||
int maxMinHeight = mInfo.getMinimumHeight();
|
int maxMinHeight = mInfo.getMinimumHeight();
|
||||||
for (Activity activity : mPendingAppearedActivities) {
|
for (IBinder activityToken : mPendingAppearedActivities) {
|
||||||
|
final Activity activity = mController.getActivity(activityToken);
|
||||||
final Size minDimensions = SplitPresenter.getMinDimensions(activity);
|
final Size minDimensions = SplitPresenter.getMinDimensions(activity);
|
||||||
if (minDimensions == null) {
|
if (minDimensions == null) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
|
|||||||
import static androidx.window.extensions.embedding.SplitRule.FINISH_ALWAYS;
|
import static androidx.window.extensions.embedding.SplitRule.FINISH_ALWAYS;
|
||||||
import static androidx.window.extensions.embedding.SplitRule.FINISH_NEVER;
|
import static androidx.window.extensions.embedding.SplitRule.FINISH_NEVER;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
@@ -45,6 +46,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
// Suppress GuardedBy warning on unit tests
|
||||||
|
@SuppressWarnings("GuardedBy")
|
||||||
public class EmbeddingTestUtils {
|
public class EmbeddingTestUtils {
|
||||||
static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200);
|
static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200);
|
||||||
static final int TASK_ID = 10;
|
static final int TASK_ID = 10;
|
||||||
@@ -191,6 +194,15 @@ public class EmbeddingTestUtils {
|
|||||||
return new TaskContainer(TASK_ID, activity);
|
return new TaskContainer(TASK_ID, activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TaskContainer createTestTaskContainer(@NonNull SplitController controller) {
|
||||||
|
final TaskContainer taskContainer = createTestTaskContainer();
|
||||||
|
final int taskId = taskContainer.getTaskId();
|
||||||
|
// Should not call to create TaskContainer with the same task id twice.
|
||||||
|
assertFalse(controller.mTaskContainers.contains(taskId));
|
||||||
|
controller.mTaskContainers.put(taskId, taskContainer);
|
||||||
|
return taskContainer;
|
||||||
|
}
|
||||||
|
|
||||||
static WindowLayoutInfo createWindowLayoutInfo() {
|
static WindowLayoutInfo createWindowLayoutInfo() {
|
||||||
final FoldingFeature foldingFeature = new FoldingFeature(
|
final FoldingFeature foldingFeature = new FoldingFeature(
|
||||||
new Rect(
|
new Rect(
|
||||||
|
|||||||
@@ -242,6 +242,14 @@ public class SplitControllerTest {
|
|||||||
|
|
||||||
assertTrue(tf.hasActivity(mActivity.getActivityToken()));
|
assertTrue(tf.hasActivity(mActivity.getActivityToken()));
|
||||||
|
|
||||||
|
// When the activity is not finishing, do not clear the record.
|
||||||
|
doReturn(false).when(mActivity).isFinishing();
|
||||||
|
mSplitController.onActivityDestroyed(mActivity);
|
||||||
|
|
||||||
|
assertTrue(tf.hasActivity(mActivity.getActivityToken()));
|
||||||
|
|
||||||
|
// Clear the record when the activity is finishing and destroyed.
|
||||||
|
doReturn(true).when(mActivity).isFinishing();
|
||||||
mSplitController.onActivityDestroyed(mActivity);
|
mSplitController.onActivityDestroyed(mActivity);
|
||||||
|
|
||||||
assertFalse(tf.hasActivity(mActivity.getActivityToken()));
|
assertFalse(tf.hasActivity(mActivity.getActivityToken()));
|
||||||
|
|||||||
@@ -161,7 +161,8 @@ public class TaskFragmentContainerTest {
|
|||||||
final TaskFragmentContainer pendingActivityContainer = new TaskFragmentContainer(mActivity,
|
final TaskFragmentContainer pendingActivityContainer = new TaskFragmentContainer(mActivity,
|
||||||
null /* pendingAppearedIntent */, taskContainer, mController);
|
null /* pendingAppearedIntent */, taskContainer, mController);
|
||||||
|
|
||||||
assertTrue(pendingActivityContainer.mPendingAppearedActivities.contains(mActivity));
|
assertTrue(pendingActivityContainer.mPendingAppearedActivities.contains(
|
||||||
|
mActivity.getActivityToken()));
|
||||||
|
|
||||||
final TaskFragmentInfo info0 = createMockTaskFragmentInfo(pendingActivityContainer,
|
final TaskFragmentInfo info0 = createMockTaskFragmentInfo(pendingActivityContainer,
|
||||||
mActivity);
|
mActivity);
|
||||||
@@ -317,7 +318,7 @@ public class TaskFragmentContainerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnActivityDestroyed() {
|
public void testOnActivityDestroyed() {
|
||||||
final TaskContainer taskContainer = createTestTaskContainer();
|
final TaskContainer taskContainer = createTestTaskContainer(mController);
|
||||||
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
|
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
|
||||||
mIntent, taskContainer, mController);
|
mIntent, taskContainer, mController);
|
||||||
container.addPendingAppearedActivity(mActivity);
|
container.addPendingAppearedActivity(mActivity);
|
||||||
@@ -328,7 +329,7 @@ public class TaskFragmentContainerTest {
|
|||||||
|
|
||||||
assertTrue(container.hasActivity(mActivity.getActivityToken()));
|
assertTrue(container.hasActivity(mActivity.getActivityToken()));
|
||||||
|
|
||||||
taskContainer.onActivityDestroyed(mActivity);
|
taskContainer.onActivityDestroyed(mActivity.getActivityToken());
|
||||||
|
|
||||||
// It should not contain the destroyed Activity.
|
// It should not contain the destroyed Activity.
|
||||||
assertFalse(container.hasActivity(mActivity.getActivityToken()));
|
assertFalse(container.hasActivity(mActivity.getActivityToken()));
|
||||||
@@ -398,6 +399,79 @@ public class TaskFragmentContainerTest {
|
|||||||
assertFalse(taskContainer.isInIntermediateState());
|
assertFalse(taskContainer.isInIntermediateState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHasAppearedActivity() {
|
||||||
|
final TaskContainer taskContainer = createTestTaskContainer();
|
||||||
|
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
|
||||||
|
mIntent, taskContainer, mController);
|
||||||
|
container.addPendingAppearedActivity(mActivity);
|
||||||
|
|
||||||
|
assertFalse(container.hasAppearedActivity(mActivity.getActivityToken()));
|
||||||
|
|
||||||
|
final List<IBinder> activities = new ArrayList<>();
|
||||||
|
activities.add(mActivity.getActivityToken());
|
||||||
|
doReturn(activities).when(mInfo).getActivities();
|
||||||
|
container.setInfo(mTransaction, mInfo);
|
||||||
|
|
||||||
|
assertTrue(container.hasAppearedActivity(mActivity.getActivityToken()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHasPendingAppearedActivity() {
|
||||||
|
final TaskContainer taskContainer = createTestTaskContainer();
|
||||||
|
final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
|
||||||
|
mIntent, taskContainer, mController);
|
||||||
|
container.addPendingAppearedActivity(mActivity);
|
||||||
|
|
||||||
|
assertTrue(container.hasPendingAppearedActivity(mActivity.getActivityToken()));
|
||||||
|
|
||||||
|
final List<IBinder> activities = new ArrayList<>();
|
||||||
|
activities.add(mActivity.getActivityToken());
|
||||||
|
doReturn(activities).when(mInfo).getActivities();
|
||||||
|
container.setInfo(mTransaction, mInfo);
|
||||||
|
|
||||||
|
assertFalse(container.hasPendingAppearedActivity(mActivity.getActivityToken()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHasActivity() {
|
||||||
|
final TaskContainer taskContainer = createTestTaskContainer(mController);
|
||||||
|
final TaskFragmentContainer container1 = new TaskFragmentContainer(null /* activity */,
|
||||||
|
mIntent, taskContainer, mController);
|
||||||
|
final TaskFragmentContainer container2 = new TaskFragmentContainer(null /* activity */,
|
||||||
|
mIntent, taskContainer, mController);
|
||||||
|
|
||||||
|
// Activity is pending appeared on container2.
|
||||||
|
container2.addPendingAppearedActivity(mActivity);
|
||||||
|
|
||||||
|
assertFalse(container1.hasActivity(mActivity.getActivityToken()));
|
||||||
|
assertTrue(container2.hasActivity(mActivity.getActivityToken()));
|
||||||
|
|
||||||
|
// Activity is pending appeared on container1 (removed from container2).
|
||||||
|
container1.addPendingAppearedActivity(mActivity);
|
||||||
|
|
||||||
|
assertTrue(container1.hasActivity(mActivity.getActivityToken()));
|
||||||
|
assertFalse(container2.hasActivity(mActivity.getActivityToken()));
|
||||||
|
|
||||||
|
final List<IBinder> activities = new ArrayList<>();
|
||||||
|
activities.add(mActivity.getActivityToken());
|
||||||
|
doReturn(activities).when(mInfo).getActivities();
|
||||||
|
|
||||||
|
// Although Activity is appeared on container2, we prioritize pending appeared record on
|
||||||
|
// container1.
|
||||||
|
container2.setInfo(mTransaction, mInfo);
|
||||||
|
|
||||||
|
assertTrue(container1.hasActivity(mActivity.getActivityToken()));
|
||||||
|
assertFalse(container2.hasActivity(mActivity.getActivityToken()));
|
||||||
|
|
||||||
|
// When the pending appeared record is removed from container1, we respect the appeared
|
||||||
|
// record in container2.
|
||||||
|
container1.removePendingAppearedActivity(mActivity.getActivityToken());
|
||||||
|
|
||||||
|
assertFalse(container1.hasActivity(mActivity.getActivityToken()));
|
||||||
|
assertTrue(container2.hasActivity(mActivity.getActivityToken()));
|
||||||
|
}
|
||||||
|
|
||||||
/** 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);
|
||||||
|
|||||||
Reference in New Issue
Block a user