diff options
| author | 2022-12-15 15:59:09 +0000 | |
|---|---|---|
| committer | 2022-12-15 15:59:09 +0000 | |
| commit | ef99fdd2ed12b033e361343a05e25f1692843f37 (patch) | |
| tree | b5c5e206859ad685b1569734749a96394769a890 /libs | |
| parent | bb4df48954ccdc5314071e7e20dfaf4eaef0fac1 (diff) | |
| parent | d74854188c1b90906107d8c9eddd6410c4ef049d (diff) | |
Merge "Allow launching placeholder when the TaskFragment is visible"
Diffstat (limited to 'libs')
6 files changed, 136 insertions, 24 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 5afb1d11ad45..5400164d9aae 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -431,12 +431,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen if (container != null) { // Cleanup if the TaskFragment vanished is not requested by the organizer. removeContainer(container); - // Make sure the top container is updated. - final TaskFragmentContainer newTopContainer = getTopActiveContainer( - container.getTaskId()); - if (newTopContainer != null) { - updateContainer(wct, newTopContainer); - } + // Make sure the containers in the Task are up-to-date. + updateContainersInTaskIfVisible(wct, container.getTaskId()); } cleanupTaskFragment(taskFragmentInfo.getFragmentToken()); } @@ -476,6 +472,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen updateContainersInTask(wct, taskContainer); } + void updateContainersInTaskIfVisible(@NonNull WindowContainerTransaction wct, int taskId) { + final TaskContainer taskContainer = getTaskContainer(taskId); + if (taskContainer != null && taskContainer.isVisible()) { + updateContainersInTask(wct, taskContainer); + } + } + private void updateContainersInTask(@NonNull WindowContainerTransaction wct, @NonNull TaskContainer taskContainer) { // Update all TaskFragments in the Task. Make a copy of the list since some may be @@ -1328,9 +1331,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen void removeContainer(@NonNull TaskFragmentContainer container) { // Remove all split containers that included this one final TaskContainer taskContainer = container.getTaskContainer(); - if (taskContainer == null) { - return; - } taskContainer.mContainers.remove(container); // Marked as a pending removal which will be removed after it is actually removed on the // server side (#onTaskFragmentVanished). @@ -1523,14 +1523,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } final TaskFragmentContainer container = getContainerWithActivity(activity); - // Don't launch placeholder if the container is occluded. - if (container != null && container != getTopActiveContainer(container.getTaskId())) { - return false; - } - - final SplitContainer splitContainer = getActiveSplitForContainer(container); - if (splitContainer != null && container.equals(splitContainer.getPrimaryContainer())) { - // Don't launch placeholder in primary split container + if (container != null && !allowLaunchPlaceholder(container)) { + // We don't allow activity in this TaskFragment to launch placeholder. return false; } @@ -1558,6 +1552,32 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return true; } + /** Whether or not to allow activity in this container to launch placeholder. */ + @GuardedBy("mLock") + private boolean allowLaunchPlaceholder(@NonNull TaskFragmentContainer container) { + final TaskFragmentContainer topContainer = getTopActiveContainer(container.getTaskId()); + if (container != topContainer) { + // The container is not the top most. + if (!container.isVisible()) { + // In case the container is visible (the one on top may be transparent), we may + // still want to launch placeholder even if it is not the top most. + return false; + } + if (topContainer.isWaitingActivityAppear()) { + // When the top container appeared info is not sent by the server yet, the visible + // check above may not be reliable. + return false; + } + } + + final SplitContainer splitContainer = getActiveSplitForContainer(container); + if (splitContainer != null && container.equals(splitContainer.getPrimaryContainer())) { + // Don't launch placeholder for primary split container. + return false; + } + return true; + } + /** * Gets the activity options for starting the placeholder activity. In case the placeholder is * launched when the Task is in the background, we don't want to bring the Task to the front. 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 47253d388f0d..a432e2b10c14 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java @@ -154,12 +154,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { void cleanupContainer(@NonNull WindowContainerTransaction wct, @NonNull TaskFragmentContainer container, boolean shouldFinishDependent) { container.finish(shouldFinishDependent, this, wct, mController); - - final TaskFragmentContainer newTopContainer = mController.getTopActiveContainer( - container.getTaskId()); - if (newTopContainer != null) { - mController.updateContainer(wct, newTopContainer); - } + // Make sure the containers in the Task is up-to-date. + mController.updateContainersInTaskIfVisible(wct, container.getTaskId()); } /** 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 fcf0ac78af38..8240874ca53d 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java @@ -184,6 +184,11 @@ class TaskFragmentContainer { return allActivities; } + /** Whether this TaskFragment is visible. */ + boolean isVisible() { + return mInfo != null && mInfo.isVisible(); + } + /** Whether the TaskFragment is in an intermediate state waiting for the server update.*/ boolean isInIntermediateState() { if (mInfo == null) { diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java index bc03e4ec303d..2f92a577baa2 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java @@ -163,11 +163,17 @@ public class EmbeddingTestUtils { /** Creates a mock TaskFragmentInfo for the given TaskFragment. */ static TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container, @NonNull Activity activity) { + return createMockTaskFragmentInfo(container, activity, true /* isVisible */); + } + + /** Creates a mock TaskFragmentInfo for the given TaskFragment. */ + static TaskFragmentInfo createMockTaskFragmentInfo(@NonNull TaskFragmentContainer container, + @NonNull Activity activity, boolean isVisible) { return new TaskFragmentInfo(container.getTaskFragmentToken(), mock(WindowContainerToken.class), new Configuration(), 1, - true /* isVisible */, + isVisible, Collections.singletonList(activity.getActivityToken()), new Point(), false /* isTaskClearedForReuse */, 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 6725dfdb94e8..3cc31f9761c1 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 @@ -1254,6 +1254,68 @@ public class SplitControllerTest { verify(mEmbeddingCallback).accept(any()); } + @Test + public void testLaunchPlaceholderIfNecessary_nonEmbeddedActivity() { + // Launch placeholder for non embedded activity. + setupPlaceholderRule(mActivity); + mTransactionManager.startNewTransaction(); + mSplitController.launchPlaceholderIfNecessary(mTransaction, mActivity, + true /* isOnCreated */); + + verify(mTransaction).startActivityInTaskFragment(any(), any(), eq(PLACEHOLDER_INTENT), + any()); + } + + @Test + public void testLaunchPlaceholderIfNecessary_embeddedInTopTaskFragment() { + // Launch placeholder for activity in top TaskFragment. + setupPlaceholderRule(mActivity); + mTransactionManager.startNewTransaction(); + final TaskFragmentContainer container = mSplitController.newContainer(mActivity, TASK_ID); + mSplitController.launchPlaceholderIfNecessary(mTransaction, mActivity, + true /* isOnCreated */); + + assertTrue(container.hasActivity(mActivity.getActivityToken())); + verify(mTransaction).startActivityInTaskFragment(any(), any(), eq(PLACEHOLDER_INTENT), + any()); + } + + @Test + public void testLaunchPlaceholderIfNecessary_embeddedBelowTaskFragment() { + // Do not launch placeholder for invisible activity below the top TaskFragment. + setupPlaceholderRule(mActivity); + mTransactionManager.startNewTransaction(); + final TaskFragmentContainer bottomTf = mSplitController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer topTf = mSplitController.newContainer(new Intent(), mActivity, + TASK_ID); + bottomTf.setInfo(mTransaction, createMockTaskFragmentInfo(bottomTf, mActivity, + false /* isVisible */)); + topTf.setInfo(mTransaction, createMockTaskFragmentInfo(topTf, createMockActivity())); + assertFalse(bottomTf.isVisible()); + mSplitController.launchPlaceholderIfNecessary(mTransaction, mActivity, + true /* isOnCreated */); + + verify(mTransaction, never()).startActivityInTaskFragment(any(), any(), any(), any()); + } + + @Test + public void testLaunchPlaceholderIfNecessary_embeddedBelowTransparentTaskFragment() { + // Launch placeholder for visible activity below the top TaskFragment. + setupPlaceholderRule(mActivity); + mTransactionManager.startNewTransaction(); + final TaskFragmentContainer bottomTf = mSplitController.newContainer(mActivity, TASK_ID); + final TaskFragmentContainer topTf = mSplitController.newContainer(new Intent(), mActivity, + TASK_ID); + bottomTf.setInfo(mTransaction, createMockTaskFragmentInfo(bottomTf, mActivity, + true /* isVisible */)); + topTf.setInfo(mTransaction, createMockTaskFragmentInfo(topTf, createMockActivity())); + assertTrue(bottomTf.isVisible()); + mSplitController.launchPlaceholderIfNecessary(mTransaction, mActivity, + true /* isOnCreated */); + + verify(mTransaction).startActivityInTaskFragment(any(), any(), any(), any()); + } + /** Creates a mock activity in the organizer process. */ private Activity createMockActivity() { return createMockActivity(TASK_ID); 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 5c3ba72e2361..98772360a321 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 @@ -500,6 +500,29 @@ public class TaskFragmentContainerTest { assertEquals(2, taskContainer.indexOf(tf1)); } + @Test + public void testIsVisible() { + final TaskContainer taskContainer = createTestTaskContainer(); + final TaskFragmentContainer container = new TaskFragmentContainer( + null /* pendingAppearedActivity */, new Intent(), taskContainer, mController, + null /* pairedPrimaryTaskFragment */); + + // Not visible when there is not appeared. + assertFalse(container.isVisible()); + + // Respect info.isVisible. + TaskFragmentInfo info = createMockTaskFragmentInfo(container, mActivity, + true /* isVisible */); + container.setInfo(mTransaction, info); + + assertTrue(container.isVisible()); + + info = createMockTaskFragmentInfo(container, mActivity, false /* isVisible */); + container.setInfo(mTransaction, info); + + assertFalse(container.isVisible()); + } + /** Creates a mock activity in the organizer process. */ private Activity createMockActivity() { final Activity activity = mock(Activity.class); |