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

Commit 1abc73c5 authored by Evan Rosky's avatar Evan Rosky
Browse files

Hook up split-launch to legacy transition system

Adds legacy versions of the animation logic.

Bug: 192279476
Test: use SPLIT_SELECT to launch 2 apps in split and observe
Change-Id: I5cbe7416819ba88d8c081fb413177fadac5b815d
parent 37f1fbf7
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.RemoteAnimationAdapter;
import android.view.SurfaceControl;

import com.android.launcher3.util.MainThreadInitializedObject;
@@ -562,6 +563,22 @@ public class SystemUiProxy implements ISystemUiProxy,
        }
    }

    /**
     * Start multiple tasks in split-screen simultaneously.
     */
    public void startTasksWithLegacyTransition(int mainTaskId, Bundle mainOptions, int sideTaskId,
            Bundle sideOptions, @SplitConfigurationOptions.StagePosition int sidePosition,
            RemoteAnimationAdapter adapter) {
        if (mSystemUiProxy != null) {
            try {
                mSplitScreen.startTasksWithLegacyTransition(mainTaskId, mainOptions, sideTaskId,
                        sideOptions, sidePosition, adapter);
            } catch (RemoteException e) {
                Log.w(TAG, "Failed call startTasksWithLegacyTransition");
            }
        }
    }

    public void startShortcut(String packageName, String shortcutId, int stage, int position,
            Bundle options, UserHandle user) {
        if (mSplitScreen != null) {
+24 −62
Original line number Diff line number Diff line
@@ -405,77 +405,39 @@ public final class TaskViewUtils {
    }

    /** Legacy version (until shell transitions are enabled) */
    public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull AnimatorSet anim,
    public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull TaskView initialView,
            @NonNull TaskView v, @NonNull RemoteAnimationTargetCompat[] appTargets,
            @NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
            @NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing,
            @NonNull StateManager stateManager, @NonNull DepthController depthController,
            int targetStage) {
        PendingAnimation out = new PendingAnimation(RECENTS_LAUNCH_DURATION);
        boolean isRunningTask = v.isRunningTask();
        TransformParams params = null;
        TaskViewSimulator tvs = null;
        RecentsView recentsView = v.getRecentsView();
        if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask) {
            params = recentsView.getLiveTileParams();
            tvs = recentsView.getLiveTileTaskViewSimulator();
        }

        boolean inLiveTileMode =
                ENABLE_QUICKSTEP_LIVE_TILE.get() && recentsView.getRunningTaskIndex() != -1;
        final RemoteAnimationTargets targets =
                new RemoteAnimationTargets(appTargets, wallpaperTargets, nonAppTargets,
                        inLiveTileMode ? MODE_CLOSING : MODE_OPENING);

        if (params == null) {
            SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v);
            targets.addReleaseCheck(applier);
            @NonNull RemoteAnimationTargetCompat[] nonAppTargets,
            @NonNull Runnable finishCallback) {

            params = new TransformParams()
                    .setSyncTransactionApplier(applier)
                    .setTargetSet(targets);
        final int[] splitRoots = new int[2];
        for (int i = 0; i < appTargets.length; ++i) {
            final int taskId = appTargets[i].taskInfo != null ? appTargets[i].taskInfo.taskId : -1;
            final int mode = appTargets[i].mode;
            if (taskId == initialView.getTask().key.id || taskId == v.getTask().key.id) {
                if (mode != MODE_OPENING) {
                    throw new IllegalStateException(
                            "Expected task to be opening, but it is " + mode);
                }
                splitRoots[taskId == initialView.getTask().key.id ? 0 : 1] = i;
            }

        Rect crop = new Rect();
        Context context = v.getContext();
        DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
        if (tvs == null && targets.apps.length > 0) {
            tvs = new TaskViewSimulator(recentsView.getContext(), recentsView.getSizeStrategy());
            tvs.setDp(dp);

            // RecentsView never updates the display rotation until swipe-up so the value may
            // be stale. Use the display value instead.
            int displayRotation = DisplayController.INSTANCE.get(recentsView.getContext())
                    .getInfo().rotation;
            tvs.getOrientationState().update(displayRotation, displayRotation);

            tvs.setPreview(targets.apps[targets.apps.length - 1]);
            tvs.fullScreenProgress.value = 0;
            tvs.recentsViewScale.value = 1;
//            tvs.setScroll(startScroll);

            // Fade in the task during the initial 20% of the animation
            out.addFloat(params, TransformParams.TARGET_ALPHA, 0, 1,
                    clampToProgress(LINEAR, 0, 0.2f));
        }

        TaskViewSimulator topMostSimulator = null;

        if (tvs != null) {
            out.setFloat(tvs.fullScreenProgress,
                    AnimatedFloat.VALUE, 1, TOUCH_RESPONSE_INTERPOLATOR);
            out.setFloat(tvs.recentsViewScale,
                    AnimatedFloat.VALUE, tvs.getFullScreenScale(), TOUCH_RESPONSE_INTERPOLATOR);
            out.setFloat(tvs.recentsViewScroll,
                    AnimatedFloat.VALUE, 0, TOUCH_RESPONSE_INTERPOLATOR);
        SurfaceControl.Transaction t = new SurfaceControl.Transaction();

            TaskViewSimulator finalTsv = tvs;
            TransformParams finalParams = params;
            out.addOnFrameCallback(() -> finalTsv.apply(finalParams));
            topMostSimulator = tvs;
        // This is where we should animate the split roots. For now, though, just make them visible.
        for (int i = 0; i < 2; ++i) {
            t.show(appTargets[splitRoots[i]].leash.getSurfaceControl());
            t.setAlpha(appTargets[splitRoots[i]].leash.getSurfaceControl(), 1.f);
        }

        anim.play(out.buildAnim());
        // This contains the initial state (before animation), so apply this at the beginning of
        // the animation.
        t.apply();

        // Once there is an animation, this should be called AFTER the animation completes.
        finishCallback.run();
    }

    public static void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
+39 −70
Original line number Diff line number Diff line
@@ -22,33 +22,26 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;

import android.animation.AnimatorSet;
import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Pair;
import android.view.Gravity;
import android.view.RemoteAnimationAdapter;
import android.view.SurfaceControl;
import android.window.TransitionInfo;

import androidx.annotation.Nullable;

import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.LauncherAnimationRunner;
import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory;
import com.android.launcher3.R;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskAnimationManager;
import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -92,37 +85,27 @@ public class SplitSelectStateController {
                    ? new int[]{mInitialTaskView.getTask().key.id, taskView.getTask().key.id}
                    : new int[]{taskView.getTask().key.id, mInitialTaskView.getTask().key.id};

            RemoteSplitLaunchAnimationRunner animationRunner =
                    new RemoteSplitLaunchAnimationRunner(mInitialTaskView, taskView);
            RemoteSplitLaunchTransitionRunner animationRunner =
                    new RemoteSplitLaunchTransitionRunner(mInitialTaskView, taskView);
            mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1],
                    null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
                    new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR));
            return;
        }
        // Assume initial mInitialTaskId is for top/left part of screen
        RemoteAnimationFactory initialSplitRunnerWrapped =  new SplitLaunchAnimationRunner(
                mInitialTaskView, 0);
        RemoteAnimationFactory secondarySplitRunnerWrapped =  new SplitLaunchAnimationRunner(
                taskView, 1);
        RemoteAnimationRunnerCompat initialSplitRunner = new LauncherAnimationRunner(
                new Handler(Looper.getMainLooper()), initialSplitRunnerWrapped,
                true /* startAtFrontOfQueue */);
        RemoteAnimationRunnerCompat secondarySplitRunner = new LauncherAnimationRunner(
                new Handler(Looper.getMainLooper()), secondarySplitRunnerWrapped,
                true /* startAtFrontOfQueue */);
        ActivityOptions initialOptions = ActivityOptionsCompat.makeRemoteAnimation(
                new RemoteAnimationAdapterCompat(initialSplitRunner, 300, 150));
        ActivityOptions secondaryOptions = ActivityOptionsCompat.makeRemoteAnimation(
                new RemoteAnimationAdapterCompat(secondarySplitRunner, 300, 150));
        mSystemUiProxy.startTask(mInitialTaskView.getTask().key.id, mInitialPosition.mStageType,
                mInitialPosition.mStagePosition,
                /*null*/ initialOptions.toBundle());
        Pair<Integer, Integer> compliment = getComplimentaryStageAndPosition(mInitialPosition);
        mSystemUiProxy.startTask(taskView.getTask().key.id, compliment.first,
                compliment.second,
                /*null*/ secondaryOptions.toBundle());
        // After successful launch, call resetState
        resetState();
        } else {
            // Assume initial task is for top/left part of screen
            final int[] taskIds = mInitialPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT
                    ? new int[]{mInitialTaskView.getTask().key.id, taskView.getTask().key.id}
                    : new int[]{taskView.getTask().key.id, mInitialTaskView.getTask().key.id};

            RemoteSplitLaunchAnimationRunner animationRunner =
                    new RemoteSplitLaunchAnimationRunner(mInitialTaskView, taskView);
            final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
                    RemoteAnimationAdapterCompat.wrapRemoteAnimationRunner(animationRunner),
                    300, 150,
                    ActivityThread.currentActivityThread().getApplicationThread());

            mSystemUiProxy.startTasksWithLegacyTransition(taskIds[0], null /* mainOptions */,
                    taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, adapter);
        }
    }

    /**
@@ -153,12 +136,12 @@ public class SplitSelectStateController {
    /**
     * Requires Shell Transitions
     */
    private class RemoteSplitLaunchAnimationRunner implements RemoteTransitionRunner {
    private class RemoteSplitLaunchTransitionRunner implements RemoteTransitionRunner {

        private final TaskView mInitialTaskView;
        private final TaskView mTaskView;

        RemoteSplitLaunchAnimationRunner(TaskView initialTaskView, TaskView taskView) {
        RemoteSplitLaunchTransitionRunner(TaskView initialTaskView, TaskView taskView) {
            mInitialTaskView = initialTaskView;
            mTaskView = taskView;
        }
@@ -173,50 +156,36 @@ public class SplitSelectStateController {
        }
    }

    /**
     * LEGACY
     * @return the opposite stage and position from the {@param position} provided as first and
     *         second object, respectively
     * Ex. If position is has stage = Main and position = Top/Left, this will return
     * Pair(stage=Side, position=Bottom/Left)
     */
    private Pair<Integer, Integer> getComplimentaryStageAndPosition(SplitPositionOption position) {
        // Right now this is as simple as flipping between 0 and 1
        int complimentStageType = position.mStageType ^ 1;
        int complimentStagePosition = position.mStagePosition ^ 1;
        return new Pair<>(complimentStageType, complimentStagePosition);
    }

    /**
     * LEGACY
     * Remote animation runner for animation to launch an app.
     */
    private class SplitLaunchAnimationRunner implements RemoteAnimationFactory {
    private class RemoteSplitLaunchAnimationRunner implements RemoteAnimationRunnerCompat {

        private final TaskView mV;
        private final int mTargetState;
        private final TaskView mInitialTaskView;
        private final TaskView mTaskView;

        RemoteSplitLaunchAnimationRunner(TaskView initialTaskView, TaskView taskView) {
            mInitialTaskView = initialTaskView;
            mTaskView = taskView;
        }

        SplitLaunchAnimationRunner(TaskView v, int targetState) {
            mV = v;
            mTargetState = targetState;
        @Override
        public void onAnimationStart(int transit, RemoteAnimationTargetCompat[] apps,
                RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps,
                Runnable finishedCallback) {
            TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(mInitialTaskView, mTaskView, apps,
                    wallpapers, nonApps, finishedCallback);
            // After successful launch, call resetState
            resetState();
        }

        @Override
        public void onCreateAnimation(int transit,
                RemoteAnimationTargetCompat[] appTargets,
                RemoteAnimationTargetCompat[] wallpaperTargets,
                RemoteAnimationTargetCompat[] nonAppTargets,
                LauncherAnimationRunner.AnimationResult result) {
            AnimatorSet anim = new AnimatorSet();
            BaseQuickstepLauncher activity = BaseActivity.fromContext(mV.getContext());
            TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(anim, mV,
                    appTargets, wallpaperTargets, nonAppTargets, true, activity.getStateManager(),
                    activity.getDepthController(), mTargetState);
            result.setAnimation(anim, activity);
        public void onAnimationCancelled() {
            resetState();
        }
    }


    /**
     * To be called if split select was cancelled
     */