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
This commit is contained in:
Jerry Chang
2021-10-20 19:03:55 +08:00
parent 430944cefb
commit d0cda70d27
4 changed files with 53 additions and 20 deletions

View File

@@ -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);

View File

@@ -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,

View File

@@ -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 */);
}
}

View File

@@ -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<SyncTransactionQueue.TransactionRunnable> mRunnableCaptor;
@Mock
private ShellTaskOrganizer mTaskOrganizer;
@Mock
private StageTaskListener.StageListenerCallbacks mCallbacks;
@Mock
private SyncTransactionQueue mSyncQueue;
@Mock
private StageTaskUnfoldController mStageTaskUnfoldController;
@Captor
private ArgumentCaptor<SyncTransactionQueue.TransactionRunnable> 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());
}
}