Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl +9 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.wm.shell.splitscreen; import android.app.PendingIntent; import android.content.Intent; import android.content.pm.ShortcutInfo; import android.os.Bundle; import android.os.UserHandle; import android.view.RemoteAnimationAdapter; Loading Loading @@ -89,7 +90,7 @@ interface ISplitScreen { float splitRatio, in RemoteAnimationAdapter adapter) = 11; /** * Start a pair of intent and task using legacy transition system. * Starts a pair of intent and task using legacy transition system. */ oneway void startIntentAndTaskWithLegacyTransition(in PendingIntent pendingIntent, in Intent fillInIntent, int taskId, in Bundle mainOptions,in Bundle sideOptions, Loading @@ -108,4 +109,11 @@ interface ISplitScreen { * does not expect split to currently be running. */ RemoteAnimationTarget[] onStartingSplitLegacy(in RemoteAnimationTarget[] appTargets) = 14; /** * Starts a pair of shortcut and task using legacy transition system. */ oneway void startShortcutAndTaskWithLegacyTransition(in ShortcutInfo shortcutInfo, int taskId, in Bundle mainOptions, in Bundle sideOptions, int sidePosition, float splitRatio, in RemoteAnimationAdapter adapter) = 15; } libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +12 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.LauncherApps; import android.content.pm.ShortcutInfo; import android.graphics.Rect; import android.os.Bundle; import android.os.RemoteException; Loading Loading @@ -787,6 +788,17 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, sidePosition, splitRatio, adapter)); } @Override public void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) { executeRemoteCallWithTaskPermission(mController, "startShortcutAndTaskWithLegacyTransition", (controller) -> controller.mStageCoordinator.startShortcutAndTaskWithLegacyTransition( shortcutInfo, taskId, mainOptions, sideOptions, sidePosition, splitRatio, adapter)); } @Override public void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId, @Nullable Bundle sideOptions, Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +84 −83 Original line number Diff line number Diff line Loading @@ -69,11 +69,11 @@ import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.PendingIntent; import android.app.WindowConfiguration; import android.content.Context; import android.content.Intent; import android.content.pm.ShortcutInfo; import android.content.res.Configuration; import android.graphics.Rect; import android.hardware.devicestate.DeviceStateManager; Loading @@ -85,7 +85,6 @@ import android.util.Log; import android.util.Slog; import android.view.Choreographer; import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; Loading Loading @@ -531,133 +530,135 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) { startWithLegacyTransition(mainTaskId, sideTaskId, null /* pendingIntent */, null /* fillInIntent */, mainOptions, sideOptions, sidePosition, splitRatio, adapter); final WindowContainerTransaction wct = new WindowContainerTransaction(); if (sideOptions == null) sideOptions = new Bundle(); addActivityOptions(sideOptions, mSideStage); wct.startTask(sideTaskId, sideOptions); startWithLegacyTransition(wct, mainTaskId, mainOptions, sidePosition, splitRatio, adapter); } /** Start an intent and a task ordered by {@code intentFirst}. */ void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, Intent fillInIntent, int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) { startWithLegacyTransition(taskId, INVALID_TASK_ID, pendingIntent, fillInIntent, mainOptions, sideOptions, sidePosition, splitRatio, adapter); final WindowContainerTransaction wct = new WindowContainerTransaction(); if (sideOptions == null) sideOptions = new Bundle(); addActivityOptions(sideOptions, mSideStage); wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions); startWithLegacyTransition(wct, taskId, mainOptions, sidePosition, splitRatio, adapter); } private void startWithLegacyTransition(int mainTaskId, int sideTaskId, @Nullable PendingIntent pendingIntent, @Nullable Intent fillInIntent, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions, void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) { final boolean withIntent = pendingIntent != null && fillInIntent != null; final WindowContainerTransaction wct = new WindowContainerTransaction(); if (sideOptions == null) sideOptions = new Bundle(); addActivityOptions(sideOptions, mSideStage); wct.startShortcut(mContext.getPackageName(), shortcutInfo, sideOptions); startWithLegacyTransition(wct, taskId, mainOptions, sidePosition, splitRatio, adapter); } private void startWithLegacyTransition(WindowContainerTransaction sideWct, int mainTaskId, @Nullable Bundle mainOptions, @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) { // Init divider first to make divider leash for remote animation target. mSplitLayout.init(); mSplitLayout.setDivideRatio(splitRatio); // Set false to avoid record new bounds with old task still on top; mShouldUpdateRecents = false; mIsDividerRemoteAnimating = true; final WindowContainerTransaction wct = new WindowContainerTransaction(); final WindowContainerTransaction evictWct = new WindowContainerTransaction(); prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct); prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct); // Need to add another wrapper here in shell so that we can inject the divider bar // and also manage the process elevation via setRunningRemote IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() { LegacyTransitions.ILegacyTransition transition = new LegacyTransitions.ILegacyTransition() { @Override public void onAnimationStart(@WindowManager.TransitionOldType int transit, RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, final IRemoteAnimationFinishedCallback finishedCallback) { RemoteAnimationTarget[] augmentedNonApps = new RemoteAnimationTarget[nonApps.length + 1]; for (int i = 0; i < nonApps.length; ++i) { augmentedNonApps[i] = nonApps[i]; } augmentedNonApps[augmentedNonApps.length - 1] = getDividerBarLegacyTarget(); public void onAnimationStart(int transit, RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback, SurfaceControl.Transaction t) { if (apps == null || apps.length == 0) { onRemoteAnimationFinished(apps); t.apply(); try { adapter.getRunner().onAnimationCancelled(mKeyguardShowing); } catch (RemoteException e) { Slog.e(TAG, "Error starting remote animation", e); } return; } // The surfaces of splitting tasks were placed with window bounds when preparing the // transition, so update divider surface separately. final RemoteAnimationTarget dividerTarget = getDividerBarLegacyTarget(); mSplitLayout.getRefDividerBounds(mTempRect1); t.setLayer(dividerTarget.leash, Integer.MAX_VALUE) .setPosition(dividerTarget.leash, mTempRect1.left, mTempRect1.top); setDividerVisibility(true, t); for (int i = 0; i < apps.length; ++i) { if (apps[i].mode == MODE_OPENING) { t.show(apps[i].leash); } } t.apply(); IRemoteAnimationFinishedCallback wrapCallback = new IRemoteAnimationFinishedCallback.Stub() { @Override public void onAnimationFinished() throws RemoteException { onRemoteAnimationFinishedOrCancelled(false /* cancel */, evictWct); onRemoteAnimationFinished(apps); finishedCallback.onAnimationFinished(); } }; Transitions.setRunningRemoteTransitionDelegate(adapter.getCallingApplication()); try { adapter.getRunner().onAnimationStart(transit, apps, wallpapers, augmentedNonApps, wrapCallback); } catch (RemoteException e) { Slog.e(TAG, "Error starting remote animation", e); } } @Override public void onAnimationCancelled(boolean isKeyguardOccluded) { onRemoteAnimationFinishedOrCancelled(true /* cancel */, evictWct); try { adapter.getRunner().onAnimationCancelled(isKeyguardOccluded); ArrayUtils.appendElement(RemoteAnimationTarget.class, nonApps, dividerTarget), wrapCallback); } catch (RemoteException e) { Slog.e(TAG, "Error starting remote animation", e); } } }; RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter( wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay()); if (mainOptions == null) { mainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle(); } else { ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions); mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter)); mainOptions = mainActivityOptions.toBundle(); } sideOptions = sideOptions != null ? sideOptions : new Bundle(); final WindowContainerTransaction wct = new WindowContainerTransaction(); setSideStagePosition(sidePosition, wct); mSplitLayout.setDivideRatio(splitRatio); if (!mMainStage.isActive()) { // Build a request WCT that will launch both apps such that task 0 is on the main stage // while task 1 is on the side stage. mMainStage.activate(wct, false /* reparent */); } updateWindowBounds(mSplitLayout, wct); wct.reorder(mRootTaskInfo.token, true); wct.setForceTranslucent(mRootTaskInfo.token, false); // Make sure the launch options will put tasks in the corresponding split roots if (mainOptions == null) mainOptions = new Bundle(); addActivityOptions(mainOptions, mMainStage); addActivityOptions(sideOptions, mSideStage); // Add task launch requests wct.startTask(mainTaskId, mainOptions); if (withIntent) { wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions); } else { wct.startTask(sideTaskId, sideOptions); } wct.merge(sideWct, true); mSyncQueue.queue(wct); mSyncQueue.runInSync(t -> { setDividerVisibility(true, t); updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */); }); updateWindowBounds(mSplitLayout, wct); wct.reorder(mRootTaskInfo.token, true); wct.setForceTranslucent(mRootTaskInfo.token, false); mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct); } private void onRemoteAnimationFinishedOrCancelled(boolean cancel, WindowContainerTransaction evictWct) { private void onRemoteAnimationFinished(RemoteAnimationTarget[] apps) { 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-instance, we should exit split and expand that app as full screen. if (!cancel && (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0)) { mMainExecutor.execute(() -> exitSplitScreen(mMainStage.getChildCount() == 0 if (apps == null || apps.length == 0) return; // If any stage has no child after finished animation, that side of the split will display // nothing. This might happen if starting the same app on the both sides while not // supporting multi-instance. Exit the split screen and expand that app to full screen. if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) { mMainExecutor.execute(() -> exitSplitScreen(mMainStage.getChildCount() == 0 ? mSideStage : mMainStage, EXIT_REASON_UNKNOWN)); } else { mSyncQueue.queue(evictWct); return; } final WindowContainerTransaction evictWct = new WindowContainerTransaction(); prepareEvictNonOpeningChildTasks(SPLIT_POSITION_TOP_OR_LEFT, apps, evictWct); prepareEvictNonOpeningChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, apps, evictWct); mSyncQueue.queue(evictWct); } /** Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl +9 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.wm.shell.splitscreen; import android.app.PendingIntent; import android.content.Intent; import android.content.pm.ShortcutInfo; import android.os.Bundle; import android.os.UserHandle; import android.view.RemoteAnimationAdapter; Loading Loading @@ -89,7 +90,7 @@ interface ISplitScreen { float splitRatio, in RemoteAnimationAdapter adapter) = 11; /** * Start a pair of intent and task using legacy transition system. * Starts a pair of intent and task using legacy transition system. */ oneway void startIntentAndTaskWithLegacyTransition(in PendingIntent pendingIntent, in Intent fillInIntent, int taskId, in Bundle mainOptions,in Bundle sideOptions, Loading @@ -108,4 +109,11 @@ interface ISplitScreen { * does not expect split to currently be running. */ RemoteAnimationTarget[] onStartingSplitLegacy(in RemoteAnimationTarget[] appTargets) = 14; /** * Starts a pair of shortcut and task using legacy transition system. */ oneway void startShortcutAndTaskWithLegacyTransition(in ShortcutInfo shortcutInfo, int taskId, in Bundle mainOptions, in Bundle sideOptions, int sidePosition, float splitRatio, in RemoteAnimationAdapter adapter) = 15; }
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +12 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.LauncherApps; import android.content.pm.ShortcutInfo; import android.graphics.Rect; import android.os.Bundle; import android.os.RemoteException; Loading Loading @@ -787,6 +788,17 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, sidePosition, splitRatio, adapter)); } @Override public void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) { executeRemoteCallWithTaskPermission(mController, "startShortcutAndTaskWithLegacyTransition", (controller) -> controller.mStageCoordinator.startShortcutAndTaskWithLegacyTransition( shortcutInfo, taskId, mainOptions, sideOptions, sidePosition, splitRatio, adapter)); } @Override public void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId, @Nullable Bundle sideOptions, Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +84 −83 Original line number Diff line number Diff line Loading @@ -69,11 +69,11 @@ import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.PendingIntent; import android.app.WindowConfiguration; import android.content.Context; import android.content.Intent; import android.content.pm.ShortcutInfo; import android.content.res.Configuration; import android.graphics.Rect; import android.hardware.devicestate.DeviceStateManager; Loading @@ -85,7 +85,6 @@ import android.util.Log; import android.util.Slog; import android.view.Choreographer; import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; Loading Loading @@ -531,133 +530,135 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) { startWithLegacyTransition(mainTaskId, sideTaskId, null /* pendingIntent */, null /* fillInIntent */, mainOptions, sideOptions, sidePosition, splitRatio, adapter); final WindowContainerTransaction wct = new WindowContainerTransaction(); if (sideOptions == null) sideOptions = new Bundle(); addActivityOptions(sideOptions, mSideStage); wct.startTask(sideTaskId, sideOptions); startWithLegacyTransition(wct, mainTaskId, mainOptions, sidePosition, splitRatio, adapter); } /** Start an intent and a task ordered by {@code intentFirst}. */ void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, Intent fillInIntent, int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) { startWithLegacyTransition(taskId, INVALID_TASK_ID, pendingIntent, fillInIntent, mainOptions, sideOptions, sidePosition, splitRatio, adapter); final WindowContainerTransaction wct = new WindowContainerTransaction(); if (sideOptions == null) sideOptions = new Bundle(); addActivityOptions(sideOptions, mSideStage); wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions); startWithLegacyTransition(wct, taskId, mainOptions, sidePosition, splitRatio, adapter); } private void startWithLegacyTransition(int mainTaskId, int sideTaskId, @Nullable PendingIntent pendingIntent, @Nullable Intent fillInIntent, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions, void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) { final boolean withIntent = pendingIntent != null && fillInIntent != null; final WindowContainerTransaction wct = new WindowContainerTransaction(); if (sideOptions == null) sideOptions = new Bundle(); addActivityOptions(sideOptions, mSideStage); wct.startShortcut(mContext.getPackageName(), shortcutInfo, sideOptions); startWithLegacyTransition(wct, taskId, mainOptions, sidePosition, splitRatio, adapter); } private void startWithLegacyTransition(WindowContainerTransaction sideWct, int mainTaskId, @Nullable Bundle mainOptions, @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) { // Init divider first to make divider leash for remote animation target. mSplitLayout.init(); mSplitLayout.setDivideRatio(splitRatio); // Set false to avoid record new bounds with old task still on top; mShouldUpdateRecents = false; mIsDividerRemoteAnimating = true; final WindowContainerTransaction wct = new WindowContainerTransaction(); final WindowContainerTransaction evictWct = new WindowContainerTransaction(); prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct); prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct); // Need to add another wrapper here in shell so that we can inject the divider bar // and also manage the process elevation via setRunningRemote IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() { LegacyTransitions.ILegacyTransition transition = new LegacyTransitions.ILegacyTransition() { @Override public void onAnimationStart(@WindowManager.TransitionOldType int transit, RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, final IRemoteAnimationFinishedCallback finishedCallback) { RemoteAnimationTarget[] augmentedNonApps = new RemoteAnimationTarget[nonApps.length + 1]; for (int i = 0; i < nonApps.length; ++i) { augmentedNonApps[i] = nonApps[i]; } augmentedNonApps[augmentedNonApps.length - 1] = getDividerBarLegacyTarget(); public void onAnimationStart(int transit, RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback, SurfaceControl.Transaction t) { if (apps == null || apps.length == 0) { onRemoteAnimationFinished(apps); t.apply(); try { adapter.getRunner().onAnimationCancelled(mKeyguardShowing); } catch (RemoteException e) { Slog.e(TAG, "Error starting remote animation", e); } return; } // The surfaces of splitting tasks were placed with window bounds when preparing the // transition, so update divider surface separately. final RemoteAnimationTarget dividerTarget = getDividerBarLegacyTarget(); mSplitLayout.getRefDividerBounds(mTempRect1); t.setLayer(dividerTarget.leash, Integer.MAX_VALUE) .setPosition(dividerTarget.leash, mTempRect1.left, mTempRect1.top); setDividerVisibility(true, t); for (int i = 0; i < apps.length; ++i) { if (apps[i].mode == MODE_OPENING) { t.show(apps[i].leash); } } t.apply(); IRemoteAnimationFinishedCallback wrapCallback = new IRemoteAnimationFinishedCallback.Stub() { @Override public void onAnimationFinished() throws RemoteException { onRemoteAnimationFinishedOrCancelled(false /* cancel */, evictWct); onRemoteAnimationFinished(apps); finishedCallback.onAnimationFinished(); } }; Transitions.setRunningRemoteTransitionDelegate(adapter.getCallingApplication()); try { adapter.getRunner().onAnimationStart(transit, apps, wallpapers, augmentedNonApps, wrapCallback); } catch (RemoteException e) { Slog.e(TAG, "Error starting remote animation", e); } } @Override public void onAnimationCancelled(boolean isKeyguardOccluded) { onRemoteAnimationFinishedOrCancelled(true /* cancel */, evictWct); try { adapter.getRunner().onAnimationCancelled(isKeyguardOccluded); ArrayUtils.appendElement(RemoteAnimationTarget.class, nonApps, dividerTarget), wrapCallback); } catch (RemoteException e) { Slog.e(TAG, "Error starting remote animation", e); } } }; RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter( wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay()); if (mainOptions == null) { mainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle(); } else { ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions); mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter)); mainOptions = mainActivityOptions.toBundle(); } sideOptions = sideOptions != null ? sideOptions : new Bundle(); final WindowContainerTransaction wct = new WindowContainerTransaction(); setSideStagePosition(sidePosition, wct); mSplitLayout.setDivideRatio(splitRatio); if (!mMainStage.isActive()) { // Build a request WCT that will launch both apps such that task 0 is on the main stage // while task 1 is on the side stage. mMainStage.activate(wct, false /* reparent */); } updateWindowBounds(mSplitLayout, wct); wct.reorder(mRootTaskInfo.token, true); wct.setForceTranslucent(mRootTaskInfo.token, false); // Make sure the launch options will put tasks in the corresponding split roots if (mainOptions == null) mainOptions = new Bundle(); addActivityOptions(mainOptions, mMainStage); addActivityOptions(sideOptions, mSideStage); // Add task launch requests wct.startTask(mainTaskId, mainOptions); if (withIntent) { wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions); } else { wct.startTask(sideTaskId, sideOptions); } wct.merge(sideWct, true); mSyncQueue.queue(wct); mSyncQueue.runInSync(t -> { setDividerVisibility(true, t); updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */); }); updateWindowBounds(mSplitLayout, wct); wct.reorder(mRootTaskInfo.token, true); wct.setForceTranslucent(mRootTaskInfo.token, false); mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct); } private void onRemoteAnimationFinishedOrCancelled(boolean cancel, WindowContainerTransaction evictWct) { private void onRemoteAnimationFinished(RemoteAnimationTarget[] apps) { 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-instance, we should exit split and expand that app as full screen. if (!cancel && (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0)) { mMainExecutor.execute(() -> exitSplitScreen(mMainStage.getChildCount() == 0 if (apps == null || apps.length == 0) return; // If any stage has no child after finished animation, that side of the split will display // nothing. This might happen if starting the same app on the both sides while not // supporting multi-instance. Exit the split screen and expand that app to full screen. if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) { mMainExecutor.execute(() -> exitSplitScreen(mMainStage.getChildCount() == 0 ? mSideStage : mMainStage, EXIT_REASON_UNKNOWN)); } else { mSyncQueue.queue(evictWct); return; } final WindowContainerTransaction evictWct = new WindowContainerTransaction(); prepareEvictNonOpeningChildTasks(SPLIT_POSITION_TOP_OR_LEFT, apps, evictWct); prepareEvictNonOpeningChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, apps, evictWct); mSyncQueue.queue(evictWct); } /** Loading