diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl index 3cfa541c1c866..d022ec15f232f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl @@ -89,9 +89,17 @@ interface ISplitScreen { /** * Version of startTasks using legacy transition system. */ - oneway void startTasksWithLegacyTransition(int mainTaskId, in Bundle mainOptions, - int sideTaskId, in Bundle sideOptions, int sidePosition, - float splitRatio, in RemoteAnimationAdapter adapter) = 11; + oneway void startTasksWithLegacyTransition(int mainTaskId, in Bundle mainOptions, + int sideTaskId, in Bundle sideOptions, int sidePosition, + float splitRatio, in RemoteAnimationAdapter adapter) = 11; + + /** + * Start a pair of intent and task using legacy transition system. + */ + oneway void startIntentAndTaskWithLegacyTransition(in PendingIntent pendingIntent, + in Intent fillInIntent, int taskId, boolean intentFirst, in Bundle mainOptions, + in Bundle sideOptions, int sidePosition, float splitRatio, + in RemoteAnimationAdapter adapter) = 12; /** * Blocking call that notifies and gets additional split-screen targets when entering @@ -100,5 +108,7 @@ interface ISplitScreen { * @param appTargets apps that will be re-parented to display area */ RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel, - in RemoteAnimationTarget[] appTargets) = 12; + in RemoteAnimationTarget[] appTargets) = 13; + + } 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 3e6dc8241f4f3..990b53a601f30 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 @@ -640,6 +640,18 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, splitRatio, adapter)); } + @Override + public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, + Intent fillInIntent, int taskId, boolean intentFirst, Bundle mainOptions, + Bundle sideOptions, int sidePosition, float splitRatio, + RemoteAnimationAdapter adapter) { + executeRemoteCallWithTaskPermission(mController, + "startIntentAndTaskWithLegacyTransition", (controller) -> + controller.mStageCoordinator.startIntentAndTaskWithLegacyTransition( + pendingIntent, fillInIntent, taskId, intentFirst, mainOptions, + sideOptions, sidePosition, splitRatio, adapter)); + } + @Override public void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId, @Nullable Bundle sideOptions, 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 a2c2f591cde0c..219530b46da47 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 @@ -57,8 +57,10 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityTaskManager; +import android.app.PendingIntent; import android.app.WindowConfiguration; import android.content.Context; +import android.content.Intent; import android.content.res.Configuration; import android.graphics.Rect; import android.hardware.devicestate.DeviceStateManager; @@ -467,6 +469,116 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mTaskOrganizer.applyTransaction(wct); } + /** Start an intent and a task ordered by {@code intentFirst}. */ + void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, Intent fillInIntent, + int taskId, boolean intentFirst, @Nullable Bundle mainOptions, + @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio, + RemoteAnimationAdapter adapter) { + // TODO: try pulling the first chunk of this method into a method so that it can be shared + // with startTasksWithLegacyTransition. So far attempts to do so result in failure in split. + + // 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; + mShouldUpdateRecents = false; + 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() { + @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(); + + IRemoteAnimationFinishedCallback wrapCallback = + new IRemoteAnimationFinishedCallback.Stub() { + @Override + public void onAnimationFinished() throws RemoteException { + mShouldUpdateRecents = true; + mSyncQueue.queue(evictWct); + mSyncQueue.runInSync(t -> setDividerVisibility(true, t)); + finishedCallback.onAnimationFinished(); + } + }; + try { + try { + ActivityTaskManager.getService().setRunningRemoteTransitionDelegate( + adapter.getCallingApplication()); + } catch (SecurityException e) { + Slog.e(TAG, "Unable to boost animation thread. This should only happen" + + " during unit tests"); + } + adapter.getRunner().onAnimationStart(transit, apps, wallpapers, + augmentedNonApps, wrapCallback); + } catch (RemoteException e) { + Slog.e(TAG, "Error starting remote animation", e); + } + } + + @Override + public void onAnimationCancelled() { + mShouldUpdateRecents = true; + mSyncQueue.queue(evictWct); + mSyncQueue.runInSync(t -> setDividerVisibility(true, t)); + try { + adapter.getRunner().onAnimationCancelled(); + } 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(); + setSideStagePosition(sidePosition, wct); + + mSplitLayout.setDivideRatio(splitRatio); + if (mMainStage.isActive()) { + mMainStage.moveToTop(getMainStageBounds(), wct); + } else { + // 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(getMainStageBounds(), wct, false /* reparent */); + } + mSideStage.moveToTop(getSideStageBounds(), wct); + + // Make sure the launch options will put tasks in the corresponding split roots + addActivityOptions(mainOptions, mMainStage); + addActivityOptions(sideOptions, mSideStage); + + // Add task launch requests + if (intentFirst) { + wct.sendPendingIntent(pendingIntent, fillInIntent, mainOptions); + wct.startTask(taskId, sideOptions); + } else { + wct.startTask(taskId, mainOptions); + wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions); + } + + // Using legacy transitions, so we can't use blast sync since it conflicts. + mTaskOrganizer.applyTransaction(wct); + } + /** * Collects all the current child tasks of a specific split and prepares transaction to evict * them to display.