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

Commit 08718392 authored by Winson Chung's avatar Winson Chung Committed by Android (Google) Code Review
Browse files

Merge "Add simple mechanism for synthetic recents transitions" into main

parents 85c2696b 4fb50c30
Loading
Loading
Loading
Loading
+47 −0
Original line number Original line Diff line number Diff line
@@ -40,6 +40,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.TaskInfo;
import android.app.WindowConfiguration;
import android.app.WindowConfiguration;
import android.graphics.Rect;
import android.graphics.Rect;
import android.util.ArrayMap;
import android.util.ArrayMap;
@@ -339,6 +340,52 @@ public class TransitionUtil {
        return target;
        return target;
    }
    }


    /**
     * Creates a new RemoteAnimationTarget from the provided change and leash
     */
    public static RemoteAnimationTarget newSyntheticTarget(ActivityManager.RunningTaskInfo taskInfo,
            SurfaceControl leash, @TransitionInfo.TransitionMode int mode, int order,
            boolean isTranslucent) {
        int taskId;
        boolean isNotInRecents;
        WindowConfiguration windowConfiguration;

        if (taskInfo != null) {
            taskId = taskInfo.taskId;
            isNotInRecents = !taskInfo.isRunning;
            windowConfiguration = taskInfo.configuration.windowConfiguration;
        } else {
            taskId = INVALID_TASK_ID;
            isNotInRecents = true;
            windowConfiguration = new WindowConfiguration();
        }

        Rect localBounds = new Rect();
        RemoteAnimationTarget target = new RemoteAnimationTarget(
                taskId,
                newModeToLegacyMode(mode),
                // TODO: once we can properly sync transactions across process,
                // then get rid of this leash.
                leash,
                isTranslucent,
                null,
                // TODO(shell-transitions): we need to send content insets? evaluate how its used.
                new Rect(0, 0, 0, 0),
                order,
                null,
                localBounds,
                new Rect(),
                windowConfiguration,
                isNotInRecents,
                null,
                new Rect(),
                taskInfo,
                false,
                INVALID_WINDOW_TYPE
        );
        return target;
    }

    private static RemoteAnimationTarget getDividerTarget(TransitionInfo.Change change,
    private static RemoteAnimationTarget getDividerTarget(TransitionInfo.Change change,
            SurfaceControl leash) {
            SurfaceControl leash) {
        return new RemoteAnimationTarget(-1 /* taskId */, newModeToLegacyMode(change.getMode()),
        return new RemoteAnimationTarget(-1 /* taskId */, newModeToLegacyMode(change.getMode()),
+0 −16
Original line number Original line Diff line number Diff line
@@ -46,7 +46,6 @@ import android.util.Log;
import android.util.SparseArray;
import android.util.SparseArray;
import android.view.SurfaceControl;
import android.view.SurfaceControl;
import android.window.ITaskOrganizerController;
import android.window.ITaskOrganizerController;
import android.window.ScreenCapture;
import android.window.StartingWindowInfo;
import android.window.StartingWindowInfo;
import android.window.StartingWindowRemovalInfo;
import android.window.StartingWindowRemovalInfo;
import android.window.TaskAppearedInfo;
import android.window.TaskAppearedInfo;
@@ -55,7 +54,6 @@ import android.window.TaskOrganizer;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.compatui.CompatUIController;
import com.android.wm.shell.compatui.CompatUIController;
import com.android.wm.shell.compatui.api.CompatUIHandler;
import com.android.wm.shell.compatui.api.CompatUIHandler;
@@ -74,7 +72,6 @@ import java.util.Arrays;
import java.util.List;
import java.util.List;
import java.util.Objects;
import java.util.Objects;
import java.util.Optional;
import java.util.Optional;
import java.util.function.Consumer;


/**
/**
 * Unified task organizer for all components in the shell.
 * Unified task organizer for all components in the shell.
@@ -561,19 +558,6 @@ public class ShellTaskOrganizer extends TaskOrganizer {
        mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskAdded(info.getTaskInfo()));
        mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskAdded(info.getTaskInfo()));
    }
    }


    /**
     * Take a screenshot of a task.
     */
    public void screenshotTask(RunningTaskInfo taskInfo, Rect crop,
            Consumer<ScreenCapture.ScreenshotHardwareBuffer> consumer) {
        final TaskAppearedInfo info = mTasks.get(taskInfo.taskId);
        if (info == null) {
            return;
        }
        ScreenshotUtils.captureLayer(info.getLeash(), crop, consumer);
    }


    @Override
    @Override
    public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
    public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
        synchronized (mLock) {
        synchronized (mLock) {
+2 −1
Original line number Original line Diff line number Diff line
@@ -487,10 +487,11 @@ public abstract class WMShellModule {
    @Provides
    @Provides
    static RecentsTransitionHandler provideRecentsTransitionHandler(
    static RecentsTransitionHandler provideRecentsTransitionHandler(
            ShellInit shellInit,
            ShellInit shellInit,
            ShellTaskOrganizer shellTaskOrganizer,
            Transitions transitions,
            Transitions transitions,
            Optional<RecentTasksController> recentTasksController,
            Optional<RecentTasksController> recentTasksController,
            HomeTransitionObserver homeTransitionObserver) {
            HomeTransitionObserver homeTransitionObserver) {
        return new RecentsTransitionHandler(shellInit, transitions,
        return new RecentsTransitionHandler(shellInit, shellTaskOrganizer, transitions,
                recentTasksController.orElse(null), homeTransitionObserver);
                recentTasksController.orElse(null), homeTransitionObserver);
    }
    }


+215 −31
Original line number Original line Diff line number Diff line
@@ -20,9 +20,12 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS;
import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_PIP;
import static android.view.WindowManager.TRANSIT_PIP;
import static android.view.WindowManager.TRANSIT_SLEEP;
import static android.view.WindowManager.TRANSIT_SLEEP;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -41,6 +44,7 @@ import android.app.PendingIntent;
import android.content.Intent;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.RemoteException;
@@ -64,6 +68,7 @@ import androidx.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
import com.android.internal.os.IResultReceiver;
import com.android.internal.protolog.ProtoLog;
import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -79,10 +84,15 @@ import java.util.function.Consumer;
 * Handles the Recents (overview) animation. Only one of these can run at a time. A recents
 * Handles the Recents (overview) animation. Only one of these can run at a time. A recents
 * transition must be created via {@link #startRecentsTransition}. Anything else will be ignored.
 * transition must be created via {@link #startRecentsTransition}. Anything else will be ignored.
 */
 */
public class RecentsTransitionHandler implements Transitions.TransitionHandler {
public class RecentsTransitionHandler implements Transitions.TransitionHandler,
        Transitions.TransitionObserver {
    private static final String TAG = "RecentsTransitionHandler";
    private static final String TAG = "RecentsTransitionHandler";


    // A placeholder for a synthetic transition that isn't backed by a true system transition
    public static final IBinder SYNTHETIC_TRANSITION = new Binder();

    private final Transitions mTransitions;
    private final Transitions mTransitions;
    private final ShellTaskOrganizer mShellTaskOrganizer;
    private final ShellExecutor mExecutor;
    private final ShellExecutor mExecutor;
    @Nullable
    @Nullable
    private final RecentTasksController mRecentTasksController;
    private final RecentTasksController mRecentTasksController;
@@ -99,19 +109,26 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
    private final HomeTransitionObserver mHomeTransitionObserver;
    private final HomeTransitionObserver mHomeTransitionObserver;
    private @Nullable Color mBackgroundColor;
    private @Nullable Color mBackgroundColor;


    public RecentsTransitionHandler(ShellInit shellInit, Transitions transitions,
    public RecentsTransitionHandler(
            @NonNull ShellInit shellInit,
            @NonNull ShellTaskOrganizer shellTaskOrganizer,
            @NonNull Transitions transitions,
            @Nullable RecentTasksController recentTasksController,
            @Nullable RecentTasksController recentTasksController,
            HomeTransitionObserver homeTransitionObserver) {
            @NonNull HomeTransitionObserver homeTransitionObserver) {
        mShellTaskOrganizer = shellTaskOrganizer;
        mTransitions = transitions;
        mTransitions = transitions;
        mExecutor = transitions.getMainExecutor();
        mExecutor = transitions.getMainExecutor();
        mRecentTasksController = recentTasksController;
        mRecentTasksController = recentTasksController;
        mHomeTransitionObserver = homeTransitionObserver;
        mHomeTransitionObserver = homeTransitionObserver;
        if (!Transitions.ENABLE_SHELL_TRANSITIONS) return;
        if (!Transitions.ENABLE_SHELL_TRANSITIONS) return;
        if (recentTasksController == null) return;
        if (recentTasksController == null) return;
        shellInit.addInitCallback(() -> {
        shellInit.addInitCallback(this::onInit, this);
            recentTasksController.setTransitionHandler(this);
    }
            transitions.addHandler(this);

        }, this);
    private void onInit() {
        mRecentTasksController.setTransitionHandler(this);
        mTransitions.addHandler(this);
        mTransitions.registerObserver(this);
    }
    }


    /** Register a mixer handler. {@see RecentsMixedHandler}*/
    /** Register a mixer handler. {@see RecentsMixedHandler}*/
@@ -138,17 +155,59 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
        mBackgroundColor = color;
        mBackgroundColor = color;
    }
    }


    /**
     * Starts a new real/synthetic recents transition.
     */
    @VisibleForTesting
    @VisibleForTesting
    public IBinder startRecentsTransition(PendingIntent intent, Intent fillIn, Bundle options,
    public IBinder startRecentsTransition(PendingIntent intent, Intent fillIn, Bundle options,
            IApplicationThread appThread, IRecentsAnimationRunner listener) {
            IApplicationThread appThread, IRecentsAnimationRunner listener) {
        // only care about latest one.
        mAnimApp = appThread;

        // TODO(b/366021931): Formalize this later
        final boolean isSyntheticRequest = options.containsKey("is_synthetic_recents_transition");
        if (isSyntheticRequest) {
            return startSyntheticRecentsTransition(listener);
        } else {
            return startRealRecentsTransition(intent, fillIn, options, listener);
        }
    }

    /**
     * Starts a synthetic recents transition that is not backed by a real WM transition.
     */
    private IBinder startSyntheticRecentsTransition(@NonNull IRecentsAnimationRunner listener) {
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
                "RecentsTransitionHandler.startRecentsTransition(synthetic)");
        final RecentsController lastController = getLastController();
        if (lastController != null) {
            lastController.cancel(lastController.isSyntheticTransition()
                    ? "existing_running_synthetic_transition"
                    : "existing_running_transition");
            return null;
        }

        // Create a new synthetic transition and start it immediately
        final RecentsController controller = new RecentsController(listener);
        controller.startSyntheticTransition();
        mControllers.add(controller);
        return SYNTHETIC_TRANSITION;
    }

    /**
     * Starts a real WM-backed recents transition.
     */
    private IBinder startRealRecentsTransition(PendingIntent intent, Intent fillIn, Bundle options,
            IRecentsAnimationRunner listener) {
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
                "RecentsTransitionHandler.startRecentsTransition");
                "RecentsTransitionHandler.startRecentsTransition");


        // only care about latest one.
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        mAnimApp = appThread;
        WindowContainerTransaction wct = new WindowContainerTransaction();
        wct.sendPendingIntent(intent, fillIn, options);
        wct.sendPendingIntent(intent, fillIn, options);
        final RecentsController controller = new RecentsController(listener);

        // Find the mixed handler which should handle this request (if we are in a state where a
        // mixed handler is needed).  This is slightly convoluted because starting the transition
        // requires the handler, but the mixed handler also needs a reference to the transition.
        RecentsMixedHandler mixer = null;
        RecentsMixedHandler mixer = null;
        Consumer<IBinder> setTransitionForMixer = null;
        Consumer<IBinder> setTransitionForMixer = null;
        for (int i = 0; i < mMixers.size(); ++i) {
        for (int i = 0; i < mMixers.size(); ++i) {
@@ -160,12 +219,11 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
        }
        }
        final IBinder transition = mTransitions.startTransition(TRANSIT_TO_FRONT, wct,
        final IBinder transition = mTransitions.startTransition(TRANSIT_TO_FRONT, wct,
                mixer == null ? this : mixer);
                mixer == null ? this : mixer);
        for (int i = 0; i < mStateListeners.size(); i++) {
            mStateListeners.get(i).onTransitionStarted(transition);
        }
        if (mixer != null) {
        if (mixer != null) {
            setTransitionForMixer.accept(transition);
            setTransitionForMixer.accept(transition);
        }
        }

        final RecentsController controller = new RecentsController(listener);
        if (transition != null) {
        if (transition != null) {
            controller.setTransition(transition);
            controller.setTransition(transition);
            mControllers.add(controller);
            mControllers.add(controller);
@@ -187,11 +245,28 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
        return null;
        return null;
    }
    }


    private int findController(IBinder transition) {
    /**
     * Returns if there is currently a pending or active recents transition.
     */
    @Nullable
    private RecentsController getLastController() {
        return !mControllers.isEmpty() ? mControllers.getLast() : null;
    }

    /**
     * Finds an existing controller for the provided {@param transition}, or {@code null} if none
     * exists.
     */
    @Nullable
    @VisibleForTesting
    RecentsController findController(@NonNull IBinder transition) {
        for (int i = mControllers.size() - 1; i >= 0; --i) {
        for (int i = mControllers.size() - 1; i >= 0; --i) {
            if (mControllers.get(i).mTransition == transition) return i;
            final RecentsController controller = mControllers.get(i);
            if (controller.mTransition == transition) {
                return controller;
            }
            }
        return -1;
        }
        return null;
    }
    }


    @Override
    @Override
@@ -199,13 +274,12 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
            SurfaceControl.Transaction startTransaction,
            SurfaceControl.Transaction startTransaction,
            SurfaceControl.Transaction finishTransaction,
            SurfaceControl.Transaction finishTransaction,
            Transitions.TransitionFinishCallback finishCallback) {
            Transitions.TransitionFinishCallback finishCallback) {
        final int controllerIdx = findController(transition);
        final RecentsController controller = findController(transition);
        if (controllerIdx < 0) {
        if (controller == null) {
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
                    "RecentsTransitionHandler.startAnimation: no controller found");
                    "RecentsTransitionHandler.startAnimation: no controller found");
            return false;
            return false;
        }
        }
        final RecentsController controller = mControllers.get(controllerIdx);
        final IApplicationThread animApp = mAnimApp;
        final IApplicationThread animApp = mAnimApp;
        mAnimApp = null;
        mAnimApp = null;
        if (!controller.start(info, startTransaction, finishTransaction, finishCallback)) {
        if (!controller.start(info, startTransaction, finishTransaction, finishCallback)) {
@@ -221,13 +295,12 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
    public void mergeAnimation(IBinder transition, TransitionInfo info,
    public void mergeAnimation(IBinder transition, TransitionInfo info,
            SurfaceControl.Transaction t, IBinder mergeTarget,
            SurfaceControl.Transaction t, IBinder mergeTarget,
            Transitions.TransitionFinishCallback finishCallback) {
            Transitions.TransitionFinishCallback finishCallback) {
        final int targetIdx = findController(mergeTarget);
        final RecentsController controller = findController(mergeTarget);
        if (targetIdx < 0) {
        if (controller == null) {
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
                    "RecentsTransitionHandler.mergeAnimation: no controller found");
                    "RecentsTransitionHandler.mergeAnimation: no controller found");
            return;
            return;
        }
        }
        final RecentsController controller = mControllers.get(targetIdx);
        controller.merge(info, t, finishCallback);
        controller.merge(info, t, finishCallback);
    }
    }


@@ -244,8 +317,21 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
        }
        }
    }
    }


    @Override
    public void onTransitionReady(@NonNull IBinder transition, @NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction) {
        RecentsController controller = findController(SYNTHETIC_TRANSITION);
        if (controller != null) {
            // Cancel the existing synthetic transition if there is one
            controller.cancel("incoming_transition");
        }
    }

    /** There is only one of these and it gets reset on finish. */
    /** There is only one of these and it gets reset on finish. */
    private class RecentsController extends IRecentsAnimationController.Stub {
    @VisibleForTesting
    class RecentsController extends IRecentsAnimationController.Stub {

        private final int mInstanceId;
        private final int mInstanceId;


        private IRecentsAnimationRunner mListener;
        private IRecentsAnimationRunner mListener;
@@ -307,7 +393,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
            mDeathHandler = () -> {
            mDeathHandler = () -> {
                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
                        "[%d] RecentsController.DeathRecipient: binder died", mInstanceId);
                        "[%d] RecentsController.DeathRecipient: binder died", mInstanceId);
                finish(mWillFinishToHome, false /* leaveHint */, null /* finishCb */);
                finishInner(mWillFinishToHome, false /* leaveHint */, null /* finishCb */,
                        "deathRecipient");
            };
            };
            try {
            try {
                mListener.asBinder().linkToDeath(mDeathHandler, 0 /* flags */);
                mListener.asBinder().linkToDeath(mDeathHandler, 0 /* flags */);
@@ -317,6 +404,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
            }
            }
        }
        }


        /**
         * Sets the started transition for this instance of the recents transition.
         */
        void setTransition(IBinder transition) {
        void setTransition(IBinder transition) {
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
                    "[%d] RecentsController.setTransition: id=%s", mInstanceId, transition);
                    "[%d] RecentsController.setTransition: id=%s", mInstanceId, transition);
@@ -330,6 +420,10 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
        }
        }


        void cancel(boolean toHome, boolean withScreenshots, String reason) {
        void cancel(boolean toHome, boolean withScreenshots, String reason) {
            if (cancelSyntheticTransition(reason)) {
                return;
            }

            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
                    "[%d] RecentsController.cancel: toHome=%b reason=%s",
                    "[%d] RecentsController.cancel: toHome=%b reason=%s",
                    mInstanceId, toHome, reason);
                    mInstanceId, toHome, reason);
@@ -341,7 +435,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
                }
                }
            }
            }
            if (mFinishCB != null) {
            if (mFinishCB != null) {
                finishInner(toHome, false /* userLeave */, null /* finishCb */);
                finishInner(toHome, false /* userLeave */, null /* finishCb */, "cancel");
            } else {
            } else {
                cleanUp();
                cleanUp();
            }
            }
@@ -436,6 +530,91 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
            }
            }
        }
        }


        /**
         * Starts a new transition that is not backed by a system transition.
         */
        void startSyntheticTransition() {
            mTransition = SYNTHETIC_TRANSITION;

            // TODO(b/366021931): Update mechanism for pulling the home task, for now add home as
            //                    both opening and closing since there's some pre-existing
            //                    dependencies on having a closing task
            final ActivityManager.RunningTaskInfo homeTask =
                    mShellTaskOrganizer.getRunningTasks(DEFAULT_DISPLAY).stream()
                            .filter(task -> task.getActivityType() == ACTIVITY_TYPE_HOME)
                            .findFirst()
                            .get();
            final RemoteAnimationTarget openingTarget = TransitionUtil.newSyntheticTarget(
                    homeTask, mShellTaskOrganizer.getHomeTaskOverlayContainer(), TRANSIT_OPEN,
                    0, true /* isTranslucent */);
            final RemoteAnimationTarget closingTarget = TransitionUtil.newSyntheticTarget(
                    homeTask, mShellTaskOrganizer.getHomeTaskOverlayContainer(), TRANSIT_CLOSE,
                    0, true /* isTranslucent */);
            final ArrayList<RemoteAnimationTarget> apps = new ArrayList<>();
            apps.add(openingTarget);
            apps.add(closingTarget);
            try {
                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
                        "[%d] RecentsController.start: calling onAnimationStart with %d apps",
                        mInstanceId, apps.size());
                mListener.onAnimationStart(this,
                        apps.toArray(new RemoteAnimationTarget[apps.size()]),
                        new RemoteAnimationTarget[0],
                        new Rect(0, 0, 0, 0), new Rect(), new Bundle());
                for (int i = 0; i < mStateListeners.size(); i++) {
                    mStateListeners.get(i).onAnimationStateChanged(true);
                }
            } catch (RemoteException e) {
                Slog.e(TAG, "Error starting recents animation", e);
                cancel("startSynthetricTransition() failed");
            }
        }

        /**
         * Returns whether this transition is backed by a real system transition or not.
         */
        boolean isSyntheticTransition() {
            return mTransition == SYNTHETIC_TRANSITION;
        }

        /**
         * Called when a synthetic transition is canceled.
         */
        boolean cancelSyntheticTransition(String reason) {
            if (!isSyntheticTransition()) {
                return false;
            }

            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
                    "[%d] RecentsController.cancelSyntheticTransition reason=%s",
                    mInstanceId, reason);
            try {
                // TODO(b/366021931): Notify the correct tasks once we build actual targets, and
                //                    clean up leashes accordingly
                mListener.onAnimationCanceled(new int[0], new TaskSnapshot[0]);
            } catch (RemoteException e) {
                Slog.e(TAG, "Error canceling previous recents animation", e);
            }
            cleanUp();
            return true;
        }

        /**
         * Called when a synthetic transition is finished.
         * @return
         */
        boolean finishSyntheticTransition() {
            if (!isSyntheticTransition()) {
                return false;
            }

            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
                    "[%d] RecentsController.finishSyntheticTransition", mInstanceId);
            // TODO(b/366021931): Clean up leashes accordingly
            cleanUp();
            return true;
        }

        boolean start(TransitionInfo info, SurfaceControl.Transaction t,
        boolean start(TransitionInfo info, SurfaceControl.Transaction t,
                SurfaceControl.Transaction finishT, Transitions.TransitionFinishCallback finishCB) {
                SurfaceControl.Transaction finishT, Transitions.TransitionFinishCallback finishCB) {
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
@@ -662,7 +841,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
                            // Set the callback once again so we can finish correctly.
                            // Set the callback once again so we can finish correctly.
                            mFinishCB = finishCB;
                            mFinishCB = finishCB;
                            finishInner(true /* toHome */, false /* userLeave */,
                            finishInner(true /* toHome */, false /* userLeave */,
                                    null /* finishCb */);
                                    null /* finishCb */, "takeOverAnimation");
                        }, updatedStates);
                        }, updatedStates);
            });
            });
        }
        }
@@ -810,7 +989,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
                sendCancelWithSnapshots();
                sendCancelWithSnapshots();
                mExecutor.executeDelayed(
                mExecutor.executeDelayed(
                        () -> finishInner(true /* toHome */, false /* userLeaveHint */,
                        () -> finishInner(true /* toHome */, false /* userLeaveHint */,
                                null /* finishCb */), 0);
                                null /* finishCb */, "merge"), 0);
                return;
                return;
            }
            }
            if (recentsOpening != null) {
            if (recentsOpening != null) {
@@ -1005,7 +1184,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
                    return;
                    return;
                }
                }
                final int displayId = mInfo.getRootCount() > 0 ? mInfo.getRoot(0).getDisplayId()
                final int displayId = mInfo.getRootCount() > 0 ? mInfo.getRoot(0).getDisplayId()
                        : Display.DEFAULT_DISPLAY;
                        : DEFAULT_DISPLAY;
                // transient launches don't receive focus automatically. Since we are taking over
                // transient launches don't receive focus automatically. Since we are taking over
                // the gesture now, take focus explicitly.
                // the gesture now, take focus explicitly.
                // This also moves recents back to top if the user gestured before a switch
                // This also moves recents back to top if the user gestured before a switch
@@ -1038,11 +1217,16 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
        @Override
        @Override
        @SuppressLint("NewApi")
        @SuppressLint("NewApi")
        public void finish(boolean toHome, boolean sendUserLeaveHint, IResultReceiver finishCb) {
        public void finish(boolean toHome, boolean sendUserLeaveHint, IResultReceiver finishCb) {
            mExecutor.execute(() -> finishInner(toHome, sendUserLeaveHint, finishCb));
            mExecutor.execute(() -> finishInner(toHome, sendUserLeaveHint, finishCb,
                    "requested"));
        }
        }


        private void finishInner(boolean toHome, boolean sendUserLeaveHint,
        private void finishInner(boolean toHome, boolean sendUserLeaveHint,
                IResultReceiver runnerFinishCb) {
                IResultReceiver runnerFinishCb, String reason) {
            if (finishSyntheticTransition()) {
                return;
            }

            if (mFinishCB == null) {
            if (mFinishCB == null) {
                Slog.e(TAG, "Duplicate call to finish");
                Slog.e(TAG, "Duplicate call to finish");
                return;
                return;
+0 −3
Original line number Original line Diff line number Diff line
@@ -24,7 +24,4 @@ public interface RecentsTransitionStateListener {
    /** Notifies whether the recents animation is running. */
    /** Notifies whether the recents animation is running. */
    default void onAnimationStateChanged(boolean running) {
    default void onAnimationStateChanged(boolean running) {
    }
    }

    /** Notifies that a recents shell transition has started. */
    default void onTransitionStarted(IBinder transition) {}
}
}
Loading