diff options
8 files changed, 97 insertions, 55 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 82f8a131ae2a..fb3605110d3f 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -422,6 +422,18 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen launchPlaceholderIfNecessary(activity); } + @VisibleForTesting + void onActivityDestroyed(@NonNull Activity activity) { + // Remove any pending appeared activity, as the server won't send finished activity to the + // organizer. + for (int i = mTaskContainers.size() - 1; i >= 0; i--) { + mTaskContainers.valueAt(i).cleanupPendingAppearedActivity(activity); + } + // We didn't trigger the callback if there were any pending appeared activities, so check + // again after the pending is removed. + updateCallbackIfNecessary(); + } + /** * Called when we have been waiting too long for the TaskFragment to become non-empty after * creation. @@ -465,12 +477,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen if (activityInTask == null) { throw new IllegalArgumentException("activityInTask must not be null,"); } - final TaskFragmentContainer container = new TaskFragmentContainer(activity, taskId, this); if (!mTaskContainers.contains(taskId)) { mTaskContainers.put(taskId, new TaskContainer(taskId)); } final TaskContainer taskContainer = mTaskContainers.get(taskId); - taskContainer.mContainers.add(container); + final TaskFragmentContainer container = new TaskFragmentContainer(activity, taskContainer, + this); if (!taskContainer.isTaskBoundsInitialized()) { // Get the initial bounds before the TaskFragment has appeared. final Rect taskBounds = SplitPresenter.getTaskBoundsFromActivity(activityInTask); @@ -500,14 +512,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen if (splitRule instanceof SplitPairRule && ((SplitPairRule) splitRule).shouldClearTop()) { removeExistingSecondaryContainers(wct, primaryContainer); } - mTaskContainers.get(primaryContainer.getTaskId()).mSplitContainers.add(splitContainer); + primaryContainer.getTaskContainer().mSplitContainers.add(splitContainer); } /** Cleanups all the dependencies when the TaskFragment is entering PIP. */ private void cleanupForEnterPip(@NonNull WindowContainerTransaction wct, @NonNull TaskFragmentContainer container) { - final int taskId = container.getTaskId(); - final TaskContainer taskContainer = mTaskContainers.get(taskId); + final TaskContainer taskContainer = container.getTaskContainer(); if (taskContainer == null) { return; } @@ -545,8 +556,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen */ void removeContainer(@NonNull TaskFragmentContainer container) { // Remove all split containers that included this one - final int taskId = container.getTaskId(); - final TaskContainer taskContainer = mTaskContainers.get(taskId); + final TaskContainer taskContainer = container.getTaskContainer(); if (taskContainer == null) { return; } @@ -637,8 +647,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen if (splitContainer == null) { return; } - final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId()) - .mSplitContainers; + final List<SplitContainer> splitContainers = container.getTaskContainer().mSplitContainers; if (splitContainer != splitContainers.get(splitContainers.size() - 1)) { // Skip position update - it isn't the topmost split. return; @@ -660,8 +669,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen */ @Nullable private SplitContainer getActiveSplitForContainer(@NonNull TaskFragmentContainer container) { - final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId()) - .mSplitContainers; + final List<SplitContainer> splitContainers = container.getTaskContainer().mSplitContainers; if (splitContainers.isEmpty()) { return null; } @@ -683,11 +691,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen private SplitContainer getActiveSplitForContainers( @NonNull TaskFragmentContainer firstContainer, @NonNull TaskFragmentContainer secondContainer) { - final List<SplitContainer> splitContainers = mTaskContainers.get(firstContainer.getTaskId()) + final List<SplitContainer> splitContainers = firstContainer.getTaskContainer() .mSplitContainers; - if (splitContainers == null) { - return null; - } for (int i = splitContainers.size() - 1; i >= 0; i--) { final SplitContainer splitContainer = splitContainers.get(i); final TaskFragmentContainer primary = splitContainer.getPrimaryContainer(); @@ -866,11 +871,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen if (container == null) { return false; } - final List<SplitContainer> splitContainers = mTaskContainers.get(container.getTaskId()) - .mSplitContainers; - if (splitContainers == null) { - return true; - } + final List<SplitContainer> splitContainers = container.getTaskContainer().mSplitContainers; for (SplitContainer splitContainer : splitContainers) { if (container.equals(splitContainer.getPrimaryContainer()) || container.equals(splitContainer.getSecondaryContainer())) { @@ -1059,6 +1060,11 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen public void onActivityConfigurationChanged(Activity activity) { SplitController.this.onActivityConfigurationChanged(activity); } + + @Override + public void onActivityPostDestroyed(Activity activity) { + SplitController.this.onActivityDestroyed(activity); + } } /** Executor that posts on the main application thread. */ 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 06c1d4ec8d32..b32f4fa67906 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java @@ -291,8 +291,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { // When placeholder is shown in split, we should keep the focus on the primary. wct.requestFocusOnTaskFragment(primaryContainer.getTaskFragmentToken()); } - final TaskContainer taskContainer = mController.getTaskContainer( - updatedContainer.getTaskId()); + final TaskContainer taskContainer = updatedContainer.getTaskContainer(); final int windowingMode = taskContainer.getWindowingModeForSplitTaskFragment( primaryRectBounds); updateTaskFragmentWindowingModeIfRegistered(wct, primaryContainer, windowingMode); @@ -456,12 +455,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { @NonNull Rect getParentContainerBounds(@NonNull TaskFragmentContainer container) { - final int taskId = container.getTaskId(); - final TaskContainer taskContainer = mController.getTaskContainer(taskId); - if (taskContainer == null) { - throw new IllegalStateException("Can't find TaskContainer taskId=" + taskId); - } - return taskContainer.getTaskBounds(); + return container.getTaskContainer().getTaskBounds(); } @NonNull diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java index 57628435419e..dba71ef21946 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java @@ -16,12 +16,14 @@ package androidx.window.extensions.embedding; +import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.Activity; import android.app.WindowConfiguration; import android.app.WindowConfiguration.WindowingMode; import android.graphics.Rect; @@ -62,6 +64,9 @@ class TaskContainer { final Set<IBinder> mFinishedContainer = new ArraySet<>(); TaskContainer(int taskId) { + if (taskId == INVALID_TASK_ID) { + throw new IllegalArgumentException("Invalid Task id"); + } mTaskId = taskId; } @@ -130,4 +135,11 @@ class TaskContainer { boolean isEmpty() { return mContainers.isEmpty() && mFinishedContainer.isEmpty(); } + + /** Removes the pending appeared activity from all TaskFragments in this Task. */ + void cleanupPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) { + for (TaskFragmentContainer container : mContainers) { + container.removePendingAppearedActivity(pendingAppearedActivity); + } + } } 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 35981d3af948..371ec7315a94 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java @@ -16,7 +16,6 @@ package androidx.window.extensions.embedding; -import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import android.annotation.NonNull; @@ -52,8 +51,9 @@ class TaskFragmentContainer { @NonNull private final IBinder mToken; - /** Parent leaf Task id. */ - private final int mTaskId; + /** Parent leaf Task. */ + @NonNull + private final TaskContainer mTaskContainer; /** * Server-provided task fragment information. @@ -100,14 +100,12 @@ 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, int taskId, + TaskFragmentContainer(@Nullable Activity activity, @NonNull TaskContainer taskContainer, @NonNull SplitController controller) { mController = controller; mToken = new Binder("TaskFragmentContainer"); - if (taskId == INVALID_TASK_ID) { - throw new IllegalArgumentException("Invalid Task id"); - } - mTaskId = taskId; + mTaskContainer = taskContainer; + taskContainer.mContainers.add(this); if (activity != null) { addPendingAppearedActivity(activity); } @@ -150,9 +148,18 @@ class TaskFragmentContainer { } void addPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) { + if (hasActivity(pendingAppearedActivity.getActivityToken())) { + return; + } + // Remove the pending activity from other TaskFragments. + mTaskContainer.cleanupPendingAppearedActivity(pendingAppearedActivity); mPendingAppearedActivities.add(pendingAppearedActivity); } + void removePendingAppearedActivity(@NonNull Activity pendingAppearedActivity) { + mPendingAppearedActivities.remove(pendingAppearedActivity); + } + boolean hasActivity(@NonNull IBinder token) { if (mInfo != null && mInfo.getActivities().contains(token)) { return true; @@ -364,7 +371,13 @@ class TaskFragmentContainer { /** Gets the parent leaf Task id. */ int getTaskId() { - return mTaskId; + return mTaskContainer.getTaskId(); + } + + /** Gets the parent Task. */ + @NonNull + TaskContainer getTaskContainer() { + return mTaskContainer; } @Override @@ -380,6 +393,7 @@ class TaskFragmentContainer { */ private String toString(boolean includeContainersToFinishOnExit) { return "TaskFragmentContainer{" + + " parentTaskId=" + getTaskId() + " token=" + mToken + " topNonFinishingActivity=" + getTopNonFinishingActivity() + " runningActivityCount=" + getRunningActivityCount() 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 7aa47ef11cb1..792a53168a0d 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 @@ -113,8 +113,9 @@ public class JetpackTaskFragmentOrganizerTest { @Test public void testExpandTaskFragment() { + final TaskContainer taskContainer = new TaskContainer(TASK_ID); final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, - TASK_ID, mSplitController); + 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 983208c974a1..34cde9bca763 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 @@ -22,8 +22,10 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; @@ -35,6 +37,7 @@ import android.app.Activity; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; +import android.os.Binder; import android.os.Handler; import android.platform.test.annotations.Presubmit; import android.window.TaskFragmentInfo; @@ -96,20 +99,18 @@ public class SplitControllerTest { @Test public void testGetTopActiveContainer() { - TaskContainer taskContainer = new TaskContainer(TASK_ID); - // tf3 is finished so is not active. - TaskFragmentContainer tf3 = mock(TaskFragmentContainer.class); - doReturn(true).when(tf3).isFinished(); - doReturn(false).when(tf3).isWaitingActivityAppear(); + 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); // tf2 has running activity so is active. - TaskFragmentContainer tf2 = mock(TaskFragmentContainer.class); + final TaskFragmentContainer tf2 = mock(TaskFragmentContainer.class); doReturn(1).when(tf2).getRunningActivityCount(); - // tf1 has no running activity so is not active. - TaskFragmentContainer tf1 = new TaskFragmentContainer(null /* activity */, TASK_ID, - mSplitController); - - taskContainer.mContainers.add(tf1); taskContainer.mContainers.add(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); mSplitController.mTaskContainers.put(TASK_ID, taskContainer); @@ -164,6 +165,18 @@ public class SplitControllerTest { } @Test + public void testOnActivityDestroyed() { + doReturn(new Binder()).when(mActivity).getActivityToken(); + final TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID); + + assertTrue(tf.hasActivity(mActivity.getActivityToken())); + + mSplitController.onActivityDestroyed(mActivity); + + assertFalse(tf.hasActivity(mActivity.getActivityToken())); + } + + @Test public void testNewContainer() { // Must pass in a valid activity. assertThrows(IllegalArgumentException.class, () -> 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 c40bab8d9ae3..0de94b0dc26f 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 @@ -137,9 +137,8 @@ public class TaskContainerTest { assertTrue(taskContainer.isEmpty()); - final TaskFragmentContainer tf = new TaskFragmentContainer(null /* activity */, TASK_ID, - mController); - taskContainer.mContainers.add(tf); + final TaskFragmentContainer tf = new TaskFragmentContainer(null /* activity */, + taskContainer, mController); assertFalse(taskContainer.isEmpty()); 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 d80f2b939bf0..ce80cbf323b2 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 @@ -76,7 +76,8 @@ public class TaskFragmentContainerTest { @Test public void testFinish() { - final TaskFragmentContainer container = new TaskFragmentContainer(mActivity, TASK_ID, + final TaskContainer taskContainer = new TaskContainer(TASK_ID); + final TaskFragmentContainer container = new TaskFragmentContainer(mActivity, taskContainer, mController); final WindowContainerTransaction wct = new WindowContainerTransaction(); @@ -107,8 +108,9 @@ public class TaskFragmentContainerTest { @Test public void testIsWaitingActivityAppear() { + final TaskContainer taskContainer = new TaskContainer(TASK_ID); final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, - TASK_ID, mController); + taskContainer, mController); assertTrue(container.isWaitingActivityAppear()); @@ -127,8 +129,9 @@ public class TaskFragmentContainerTest { @Test public void testAppearEmptyTimeout() { + final TaskContainer taskContainer = new TaskContainer(TASK_ID); final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */, - TASK_ID, mController); + taskContainer, mController); assertNull(container.mAppearEmptyTimeout); |