Add error handling for start task and intent
If user start task and intent with same app but not support multi-instance, in this case it will only start one side split and the other one show as black screen. We should avoid such status and do some error handling, this patch prevent it by exiting split immediately and expand the that app as full screen. Fix: 224888879 Test: manual Test: pass existing tests Change-Id: I827debb01f3a2fc8f04f4b1931084f2fa475f8a6
This commit is contained in:
@@ -190,7 +190,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
|
||||
mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
|
||||
mTaskOrganizer, mDisplayController, mDisplayImeController,
|
||||
mDisplayInsetsController, mTransitions, mTransactionPool, mLogger,
|
||||
mIconProvider, mRecentTasksOptional, mUnfoldControllerProvider);
|
||||
mIconProvider, mMainExecutor, mRecentTasksOptional, mUnfoldControllerProvider);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.common.DisplayImeController;
|
||||
import com.android.wm.shell.common.DisplayInsetsController;
|
||||
import com.android.wm.shell.common.DisplayLayout;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||
import com.android.wm.shell.common.TransactionPool;
|
||||
import com.android.wm.shell.common.split.SplitLayout;
|
||||
@@ -157,6 +158,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
private final TransactionPool mTransactionPool;
|
||||
private final SplitScreenTransitions mSplitTransitions;
|
||||
private final SplitscreenEventLogger mLogger;
|
||||
private final ShellExecutor mMainExecutor;
|
||||
private final Optional<RecentTasksController> mRecentTasks;
|
||||
|
||||
/**
|
||||
@@ -196,13 +198,15 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
DisplayImeController displayImeController,
|
||||
DisplayInsetsController displayInsetsController, Transitions transitions,
|
||||
TransactionPool transactionPool, SplitscreenEventLogger logger,
|
||||
IconProvider iconProvider, Optional<RecentTasksController> recentTasks,
|
||||
IconProvider iconProvider, ShellExecutor mainExecutor,
|
||||
Optional<RecentTasksController> recentTasks,
|
||||
Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
|
||||
mContext = context;
|
||||
mDisplayId = displayId;
|
||||
mSyncQueue = syncQueue;
|
||||
mTaskOrganizer = taskOrganizer;
|
||||
mLogger = logger;
|
||||
mMainExecutor = mainExecutor;
|
||||
mRecentTasks = recentTasks;
|
||||
mMainUnfoldController = unfoldControllerProvider.get().orElse(null);
|
||||
mSideUnfoldController = unfoldControllerProvider.get().orElse(null);
|
||||
@@ -247,7 +251,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
DisplayController displayController, DisplayImeController displayImeController,
|
||||
DisplayInsetsController displayInsetsController, SplitLayout splitLayout,
|
||||
Transitions transitions, TransactionPool transactionPool,
|
||||
SplitscreenEventLogger logger,
|
||||
SplitscreenEventLogger logger, ShellExecutor mainExecutor,
|
||||
Optional<RecentTasksController> recentTasks,
|
||||
Provider<Optional<StageTaskUnfoldController>> unfoldControllerProvider) {
|
||||
mContext = context;
|
||||
@@ -266,6 +270,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
mMainUnfoldController = unfoldControllerProvider.get().orElse(null);
|
||||
mSideUnfoldController = unfoldControllerProvider.get().orElse(null);
|
||||
mLogger = logger;
|
||||
mMainExecutor = mainExecutor;
|
||||
mRecentTasks = recentTasks;
|
||||
mDisplayController.addDisplayWindowListener(this);
|
||||
mDisplayLayout = new DisplayLayout();
|
||||
@@ -394,6 +399,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
@Nullable PendingIntent pendingIntent, @Nullable Intent fillInIntent,
|
||||
@Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
|
||||
@SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
|
||||
final boolean withIntent = pendingIntent != null && fillInIntent != null;
|
||||
// Init divider first to make divider leash for remote animation target.
|
||||
mSplitLayout.init();
|
||||
// Set false to avoid record new bounds with old task still on top;
|
||||
@@ -423,10 +429,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
new IRemoteAnimationFinishedCallback.Stub() {
|
||||
@Override
|
||||
public void onAnimationFinished() throws RemoteException {
|
||||
mIsDividerRemoteAnimating = false;
|
||||
mShouldUpdateRecents = true;
|
||||
mSyncQueue.queue(evictWct);
|
||||
mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
|
||||
onRemoteAnimationFinishedOrCancelled(evictWct);
|
||||
finishedCallback.onAnimationFinished();
|
||||
}
|
||||
};
|
||||
@@ -447,10 +450,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
|
||||
@Override
|
||||
public void onAnimationCancelled() {
|
||||
mIsDividerRemoteAnimating = false;
|
||||
mShouldUpdateRecents = true;
|
||||
mSyncQueue.queue(evictWct);
|
||||
mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
|
||||
onRemoteAnimationFinishedOrCancelled(evictWct);
|
||||
try {
|
||||
adapter.getRunner().onAnimationCancelled();
|
||||
} catch (RemoteException e) {
|
||||
@@ -486,20 +486,37 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
addActivityOptions(sideOptions, mSideStage);
|
||||
|
||||
// Add task launch requests
|
||||
if (pendingIntent != null && fillInIntent != null) {
|
||||
wct.startTask(mainTaskId, mainOptions);
|
||||
wct.startTask(mainTaskId, mainOptions);
|
||||
if (withIntent) {
|
||||
wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions);
|
||||
} else {
|
||||
wct.startTask(mainTaskId, mainOptions);
|
||||
wct.startTask(sideTaskId, sideOptions);
|
||||
}
|
||||
|
||||
// Using legacy transitions, so we can't use blast sync since it conflicts.
|
||||
mTaskOrganizer.applyTransaction(wct);
|
||||
mSyncQueue.runInSync(t ->
|
||||
updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */));
|
||||
}
|
||||
|
||||
private void onRemoteAnimationFinishedOrCancelled(WindowContainerTransaction evictWct) {
|
||||
mIsDividerRemoteAnimating = false;
|
||||
mShouldUpdateRecents = true;
|
||||
// If any stage has no child after animation finished, it means that split will display
|
||||
// nothing, such status will happen if task and intent is same app but not support
|
||||
// multi-instagce, we should exit split and expand that app as full screen.
|
||||
if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
|
||||
mMainExecutor.execute(() ->
|
||||
exitSplitScreen(mMainStage.getChildCount() == 0
|
||||
? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
|
||||
} else {
|
||||
mSyncQueue.queue(evictWct);
|
||||
mSyncQueue.runInSync(t -> {
|
||||
setDividerVisibility(true, t);
|
||||
updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects all the current child tasks of a specific split and prepares transaction to evict
|
||||
* them to display.
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.android.wm.shell.TestRunningTaskInfoBuilder;
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.common.DisplayImeController;
|
||||
import com.android.wm.shell.common.DisplayInsetsController;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||
import com.android.wm.shell.common.TransactionPool;
|
||||
import com.android.wm.shell.common.split.SplitLayout;
|
||||
@@ -72,11 +73,13 @@ public class SplitTestUtils {
|
||||
DisplayController displayController, DisplayImeController imeController,
|
||||
DisplayInsetsController insetsController, SplitLayout splitLayout,
|
||||
Transitions transitions, TransactionPool transactionPool,
|
||||
SplitscreenEventLogger logger, Optional<RecentTasksController> recentTasks,
|
||||
SplitscreenEventLogger logger, ShellExecutor mainExecutor,
|
||||
Optional<RecentTasksController> recentTasks,
|
||||
Provider<Optional<StageTaskUnfoldController>> unfoldController) {
|
||||
super(context, displayId, syncQueue, taskOrganizer, mainStage,
|
||||
sideStage, displayController, imeController, insetsController, splitLayout,
|
||||
transitions, transactionPool, logger, recentTasks, unfoldController);
|
||||
transitions, transactionPool, logger, mainExecutor, recentTasks,
|
||||
unfoldController);
|
||||
|
||||
// Prepare root task for testing.
|
||||
mRootTask = new TestRunningTaskInfoBuilder().build();
|
||||
|
||||
@@ -97,6 +97,7 @@ public class SplitTransitionTests extends ShellTestCase {
|
||||
@Mock private SurfaceSession mSurfaceSession;
|
||||
@Mock private SplitscreenEventLogger mLogger;
|
||||
@Mock private IconProvider mIconProvider;
|
||||
@Mock private ShellExecutor mMainExecutor;
|
||||
private SplitLayout mSplitLayout;
|
||||
private MainStage mMainStage;
|
||||
private SideStage mSideStage;
|
||||
@@ -126,7 +127,7 @@ public class SplitTransitionTests extends ShellTestCase {
|
||||
mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
|
||||
mSyncQueue, mTaskOrganizer, mMainStage, mSideStage, mDisplayController,
|
||||
mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions,
|
||||
mTransactionPool, mLogger, Optional.empty(), Optional::empty);
|
||||
mTransactionPool, mLogger, mMainExecutor, Optional.empty(), Optional::empty);
|
||||
mSplitScreenTransitions = mStageCoordinator.getSplitTransitions();
|
||||
doAnswer((Answer<IBinder>) invocation -> mock(IBinder.class))
|
||||
.when(mTransitions).startTransition(anyInt(), any(), any());
|
||||
|
||||
@@ -54,6 +54,7 @@ import com.android.wm.shell.TestRunningTaskInfoBuilder;
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.common.DisplayImeController;
|
||||
import com.android.wm.shell.common.DisplayInsetsController;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||
import com.android.wm.shell.common.TransactionPool;
|
||||
import com.android.wm.shell.common.split.SplitLayout;
|
||||
@@ -101,6 +102,8 @@ public class StageCoordinatorTests extends ShellTestCase {
|
||||
private TransactionPool mTransactionPool;
|
||||
@Mock
|
||||
private SplitscreenEventLogger mLogger;
|
||||
@Mock
|
||||
private ShellExecutor mMainExecutor;
|
||||
|
||||
private final Rect mBounds1 = new Rect(10, 20, 30, 40);
|
||||
private final Rect mBounds2 = new Rect(5, 10, 15, 20);
|
||||
@@ -116,7 +119,7 @@ public class StageCoordinatorTests extends ShellTestCase {
|
||||
mStageCoordinator = spy(new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
|
||||
mTaskOrganizer, mMainStage, mSideStage, mDisplayController, mDisplayImeController,
|
||||
mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool, mLogger,
|
||||
Optional.empty(), new UnfoldControllerProvider()));
|
||||
mMainExecutor, Optional.empty(), new UnfoldControllerProvider()));
|
||||
doNothing().when(mStageCoordinator).updateActivityOptions(any(), anyInt());
|
||||
|
||||
when(mSplitLayout.getBounds1()).thenReturn(mBounds1);
|
||||
|
||||
Reference in New Issue
Block a user