From d0cda70d2774bd6fd6745c1f2f6af09ced29f554 Mon Sep 17 00:00:00 2001 From: Jerry Chang Date: Wed, 20 Oct 2021 19:03:55 +0800 Subject: [PATCH] Fix drop to enter split not working Sometimes when dropping app icon to enter split screen, it'll exit split screen immediatlly because it evicts newly launched task before the task considered to be visible. Update to collect child tasks to evict before launching activity. Fix: 203610931 Fix: 203636251 Test: atest WMShellUnitTests Change-Id: If070fb5b3eb0b3fc178122d38b2dce3072621449 --- .../splitscreen/SplitScreenController.java | 18 ++++++---- .../shell/splitscreen/StageCoordinator.java | 14 +++++--- .../shell/splitscreen/StageTaskListener.java | 7 ++-- .../splitscreen/StageTaskListenerTests.java | 34 +++++++++++++++---- 4 files changed, 53 insertions(+), 20 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index ec71fbee9a294..3b75bfb933c9b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -215,10 +215,12 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, options = mStageCoordinator.resolveStartStage(stage, position, options, null /* wct */); try { + final WindowContainerTransaction evictWct = new WindowContainerTransaction(); + mStageCoordinator.prepareEvictChildTasks(position, evictWct); final int result = ActivityTaskManager.getService().startActivityFromRecents(taskId, options); if (result == START_SUCCESS || result == START_TASK_TO_FRONT) { - mStageCoordinator.evictOccludedChildren(position); + mSyncQueue.queue(evictWct); } } catch (RemoteException e) { Slog.e(TAG, "Failed to launch task", e); @@ -229,13 +231,15 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, @SplitScreen.StageType int stage, @SplitPosition int position, @Nullable Bundle options, UserHandle user) { options = mStageCoordinator.resolveStartStage(stage, position, options, null /* wct */); + final WindowContainerTransaction evictWct = new WindowContainerTransaction(); + mStageCoordinator.prepareEvictChildTasks(position, evictWct); try { LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class); launcherApps.startShortcut(packageName, shortcutId, null /* sourceBounds */, options, user); - mStageCoordinator.evictOccludedChildren(position); + mSyncQueue.queue(evictWct); } catch (ActivityNotFoundException e) { Slog.e(TAG, "Failed to launch shortcut", e); } @@ -255,6 +259,9 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, private void startIntentLegacy(PendingIntent intent, Intent fillInIntent, @SplitScreen.StageType int stage, @SplitPosition int position, @Nullable Bundle options) { + final WindowContainerTransaction evictWct = new WindowContainerTransaction(); + mStageCoordinator.prepareEvictChildTasks(position, evictWct); + LegacyTransitions.ILegacyTransition transition = new LegacyTransitions.ILegacyTransition() { @Override public void onAnimationStart(int transit, RemoteAnimationTarget[] apps, @@ -280,12 +287,11 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, } } - // Launching a new app into a specific split evicts tasks previously in the same - // split. - mStageCoordinator.evictOccludedChildren(position); + mSyncQueue.queue(evictWct); } }; - WindowContainerTransaction wct = new WindowContainerTransaction(); + + final WindowContainerTransaction wct = new WindowContainerTransaction(); options = mStageCoordinator.resolveStartStage(stage, position, options, wct); wct.sendPendingIntent(intent, fillInIntent, options); mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 0cff18e2ba85f..72d9880d0aa1a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -394,10 +394,16 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct, remoteTransition, this); } - void evictOccludedChildren(@SplitPosition int position) { - final WindowContainerTransaction wct = new WindowContainerTransaction(); - (position == mSideStagePosition ? mSideStage : mMainStage).evictOccludedChildren(wct); - mTaskOrganizer.applyTransaction(wct); + /** + * Collects all the current child tasks of a specific split and prepares transaction to evict + * them to display. + */ + void prepareEvictChildTasks(@SplitPosition int position, WindowContainerTransaction wct) { + if (position == mSideStagePosition) { + mSideStage.evictAllChildren(wct); + } else { + mMainStage.evictAllChildren(wct); + } } Bundle resolveStartStage(@SplitScreen.StageType int stage, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index 071badf2bc23a..6f1a09dc88e62 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -248,12 +248,11 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { wct.reorder(mChildrenTaskInfo.get(taskId).token, onTop /* onTop */); } - void evictOccludedChildren(WindowContainerTransaction wct) { + /** Collects all the current child tasks and prepares transaction to evict them to display. */ + void evictAllChildren(WindowContainerTransaction wct) { for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) { final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i); - if (!taskInfo.isVisible) { - wct.reparent(taskInfo.token, null /* parent */, false /* onTop */); - } + wct.reparent(taskInfo.token, null /* parent */, false /* onTop */); } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java index a5746a49da2b9..3ed72e2c079e3 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java @@ -21,6 +21,8 @@ import static android.view.Display.DEFAULT_DISPLAY; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeFalse; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; @@ -31,6 +33,7 @@ import android.app.ActivityManager; import android.os.SystemProperties; import android.view.SurfaceControl; import android.view.SurfaceSession; +import android.window.WindowContainerTransaction; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -50,7 +53,7 @@ import org.mockito.MockitoAnnotations; /** * Tests for {@link StageTaskListener} * Build/Install/Run: - * atest WMShellUnitTests:StageTaskListenerTests + * atest WMShellUnitTests:StageTaskListenerTests */ @SmallTest @RunWith(AndroidJUnit4.class) @@ -58,11 +61,16 @@ public final class StageTaskListenerTests { private static final boolean ENABLE_SHELL_TRANSITIONS = SystemProperties.getBoolean("persist.debug.shell_transit", false); - @Mock private ShellTaskOrganizer mTaskOrganizer; - @Mock private StageTaskListener.StageListenerCallbacks mCallbacks; - @Mock private SyncTransactionQueue mSyncQueue; - @Mock private StageTaskUnfoldController mStageTaskUnfoldController; - @Captor private ArgumentCaptor mRunnableCaptor; + @Mock + private ShellTaskOrganizer mTaskOrganizer; + @Mock + private StageTaskListener.StageListenerCallbacks mCallbacks; + @Mock + private SyncTransactionQueue mSyncQueue; + @Mock + private StageTaskUnfoldController mStageTaskUnfoldController; + @Captor + private ArgumentCaptor mRunnableCaptor; private SurfaceSession mSurfaceSession = new SurfaceSession(); private SurfaceControl mSurfaceControl; private ActivityManager.RunningTaskInfo mRootTask; @@ -167,4 +175,18 @@ public final class StageTaskListenerTests { mStageTaskListener.onTaskInfoChanged(childTask); verify(mCallbacks).onNoLongerSupportMultiWindow(); } + + @Test + public void testEvictAllChildren() { + final WindowContainerTransaction wct = new WindowContainerTransaction(); + mStageTaskListener.evictAllChildren(wct); + assertTrue(wct.isEmpty()); + + final ActivityManager.RunningTaskInfo childTask = + new TestRunningTaskInfoBuilder().setParentTaskId(mRootTask.taskId).build(); + mStageTaskListener.onTaskAppeared(childTask, mSurfaceControl); + + mStageTaskListener.evictAllChildren(wct); + assertFalse(wct.isEmpty()); + } }