Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 275a1a4b authored by Tracy Zhou's avatar Tracy Zhou
Browse files

Support launching intent and task in split screen

Bug: 216829535
Test: see the other cl in the same topic
Change-Id: Id0f58a788585e2dabeae476b8a2bd80ba85bb9fe
parent 849d2442
Loading
Loading
Loading
Loading
+14 −4
Original line number Diff line number Diff line
@@ -93,6 +93,14 @@ interface ISplitScreen {
            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
     * recents (for example: the dividerBar).
@@ -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;


}
+12 −0
Original line number Diff line number Diff line
@@ -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,
+112 −0
Original line number Diff line number Diff line
@@ -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.