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

Commit 242f0a52 authored by Evan Rosky's avatar Evan Rosky Committed by Automerger Merge Worker
Browse files

Merge "re-organize recents transition code for future changes" into udc-dev am: ca939575

parents 619effa3 ca939575
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -63,7 +63,7 @@ interface IWindowOrganizerController {
     * @param transitionToken A token associated with the transition to start.
     * @param t Operations that are part of the transition.
     */
    oneway void startTransition(IBinder transitionToken, in @nullable WindowContainerTransaction t);
    void startTransition(IBinder transitionToken, in @nullable WindowContainerTransaction t);

    /**
     * Starts a legacy transition.
+14 −7
Original line number Diff line number Diff line
@@ -709,15 +709,22 @@ public class Transitions implements RemoteCallable<Transitions> {
        for (int iA = activeIdx + 1; iA < mActiveTransitions.size(); ++iA) {
            final ActiveTransition toMerge = mActiveTransitions.get(iA);
            if (!toMerge.mMerged) break;
            // aborted transitions have no start/finish transactions
            if (mActiveTransitions.get(iA).mStartT == null) break;
            if (fullFinish == null) {
                fullFinish = new SurfaceControl.Transaction();
            }
            // Include start. It will be a no-op if it was already applied. Otherwise, we need it
            // to maintain consistent state.
            fullFinish.merge(mActiveTransitions.get(iA).mStartT);
            fullFinish.merge(mActiveTransitions.get(iA).mFinishT);
            if (toMerge.mStartT != null) {
                if (fullFinish == null) {
                    fullFinish = toMerge.mStartT;
                } else {
                    fullFinish.merge(toMerge.mStartT);
                }
            }
            if (toMerge.mFinishT != null) {
                if (fullFinish == null) {
                    fullFinish = toMerge.mFinishT;
                } else {
                    fullFinish.merge(toMerge.mFinishT);
                }
            }
        }
        if (fullFinish != null) {
            fullFinish.apply();
+55 −23
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.TaskInfo;
import android.app.WindowConfiguration;
import android.graphics.Rect;
import android.util.ArrayMap;
@@ -48,7 +47,7 @@ import android.window.TransitionInfo;
import android.window.TransitionInfo.Change;

import java.util.ArrayList;
import java.util.function.BiPredicate;
import java.util.function.Predicate;

/**
 * Some utility methods for creating {@link RemoteAnimationTarget} instances.
@@ -145,6 +144,18 @@ public class RemoteAnimationTargetCompat {
    public static RemoteAnimationTarget newTarget(TransitionInfo.Change change, int order,
            TransitionInfo info, SurfaceControl.Transaction t,
            @Nullable ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
        final SurfaceControl leash = createLeash(info, change, order, t);
        if (leashMap != null) {
            leashMap.put(change.getLeash(), leash);
        }
        return newTarget(change, order, leash);
    }

    /**
     * Creates a new RemoteAnimationTarget from the provided change and leash
     */
    public static RemoteAnimationTarget newTarget(TransitionInfo.Change change, int order,
            SurfaceControl leash) {
        int taskId;
        boolean isNotInRecents;
        ActivityManager.RunningTaskInfo taskInfo;
@@ -169,7 +180,7 @@ public class RemoteAnimationTargetCompat {
                newModeToLegacyMode(change.getMode()),
                // TODO: once we can properly sync transactions across process,
                // then get rid of this leash.
                createLeash(info, change, order, t),
                leash,
                (change.getFlags() & TransitionInfo.FLAG_TRANSLUCENT) != 0,
                null,
                // TODO(shell-transitions): we need to send content insets? evaluate how its used.
@@ -190,9 +201,6 @@ public class RemoteAnimationTargetCompat {
        target.setWillShowImeOnTarget(
                (change.getFlags() & TransitionInfo.FLAG_WILL_IME_SHOWN) != 0);
        target.setRotationChange(change.getEndRotation() - change.getStartRotation());
        if (leashMap != null) {
            leashMap.put(change.getLeash(), target.leash);
        }
        return target;
    }

@@ -204,18 +212,7 @@ public class RemoteAnimationTargetCompat {
     */
    public static RemoteAnimationTarget[] wrapApps(TransitionInfo info,
            SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
        SparseBooleanArray childTaskTargets = new SparseBooleanArray();
        return wrap(info, t, leashMap, (change, taskInfo) -> {
            // Children always come before parent since changes are in top-to-bottom z-order.
            if ((taskInfo == null) || childTaskTargets.get(taskInfo.taskId)) {
                // has children, so not a leaf. Skip.
                return false;
            }
            if (taskInfo.hasParentTask()) {
                childTaskTargets.put(taskInfo.parentTaskId, true);
            }
            return true;
        });
        return wrap(info, t, leashMap, new LeafTaskFilter());
    }

    /**
@@ -228,21 +225,56 @@ public class RemoteAnimationTargetCompat {
     */
    public static RemoteAnimationTarget[] wrapNonApps(TransitionInfo info, boolean wallpapers,
            SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
        return wrap(info, t, leashMap, (change, taskInfo) -> (taskInfo == null)
                && wallpapers == change.hasFlags(FLAG_IS_WALLPAPER)
                && !change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY));
        return wrap(info, t, leashMap, (change) ->
                (wallpapers ? isWallpaper(change) : isNonApp(change)));
    }

    private static RemoteAnimationTarget[] wrap(TransitionInfo info,
            SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap,
            BiPredicate<Change, TaskInfo> filter) {
            Predicate<Change> filter) {
        final ArrayList<RemoteAnimationTarget> out = new ArrayList<>();
        for (int i = 0; i < info.getChanges().size(); i++) {
            TransitionInfo.Change change = info.getChanges().get(i);
            if (filter.test(change, change.getTaskInfo())) {
            if (filter.test(change)) {
                out.add(newTarget(change, info.getChanges().size() - i, info, t, leashMap));
            }
        }
        return out.toArray(new RemoteAnimationTarget[out.size()]);
    }

    /** Returns `true` if `change` is a wallpaper. */
    public static boolean isWallpaper(Change change) {
        return (change.getTaskInfo() == null)
                && change.hasFlags(FLAG_IS_WALLPAPER)
                && !change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY);
    }

    /** Returns `true` if `change` is not an app window or wallpaper. */
    public static boolean isNonApp(Change change) {
        return (change.getTaskInfo() == null)
                && !change.hasFlags(FLAG_IS_WALLPAPER)
                && !change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY);
    }

    /**
     * Filter that selects leaf-tasks only. THIS IS ORDER-DEPENDENT! For it to work properly, you
     * MUST call `test` in the same order that the changes appear in the TransitionInfo.
     */
    public static class LeafTaskFilter implements Predicate<Change> {
        private final SparseBooleanArray mChildTaskTargets = new SparseBooleanArray();

        @Override
        public boolean test(Change change) {
            final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
            // Children always come before parent since changes are in top-to-bottom z-order.
            if ((taskInfo == null) || mChildTaskTargets.get(taskInfo.taskId)) {
                // has children, so not a leaf. Skip.
                return false;
            }
            if (taskInfo.hasParentTask()) {
                mChildTaskTargets.put(taskInfo.parentTaskId, true);
            }
            return true;
        }
    }
}
+76 −82
Original line number Diff line number Diff line
@@ -72,71 +72,23 @@ public class RemoteTransitionCompat {
            public void startAnimation(IBinder transition, TransitionInfo info,
                    SurfaceControl.Transaction t,
                    IRemoteTransitionFinishedCallback finishedCallback) {
                final ArrayMap<SurfaceControl, SurfaceControl> leashMap = new ArrayMap<>();
                final RemoteAnimationTarget[] apps =
                        RemoteAnimationTargetCompat.wrapApps(info, t, leashMap);
                final RemoteAnimationTarget[] wallpapers =
                        RemoteAnimationTargetCompat.wrapNonApps(
                                info, true /* wallpapers */, t, leashMap);
                // TODO(b/177438007): Move this set-up logic into launcher's animation impl.
                mToken = transition;
                // This transition is for opening recents, so recents is on-top. We want to draw
                // the current going-away tasks on top of recents, though, so move them to front.
                // Note that we divide up the "layer space" into 3 regions each the size of
                // the change count. This way we can easily move changes into above/below/between
                // while maintaining their relative ordering.
                final ArrayList<WindowContainerToken> pausingTasks = new ArrayList<>();
                WindowContainerToken pipTask = null;
                WindowContainerToken recentsTask = null;
                int recentsTaskId = -1;
                for (int i = apps.length - 1; i >= 0; --i) {
                    final ActivityManager.RunningTaskInfo taskInfo = apps[i].taskInfo;
                    if (apps[i].mode == MODE_CLOSING) {
                        t.setLayer(apps[i].leash, info.getChanges().size() * 3 - i);
                        if (taskInfo == null) {
                            continue;
                        }
                        // Add to front since we are iterating backwards.
                        pausingTasks.add(0, taskInfo.token);
                        if (taskInfo.pictureInPictureParams != null
                                && taskInfo.pictureInPictureParams.isAutoEnterEnabled()) {
                            pipTask = taskInfo.token;
                        }
                    } else if (taskInfo != null
                            && taskInfo.topActivityType == ACTIVITY_TYPE_RECENTS) {
                        // This task is for recents, keep it on top.
                        t.setLayer(apps[i].leash, info.getChanges().size() * 3 - i);
                        recentsTask = taskInfo.token;
                        recentsTaskId = taskInfo.taskId;
                    } else if (taskInfo != null && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
                        recentsTask = taskInfo.token;
                        recentsTaskId = taskInfo.taskId;
                    }
                }
                // Also make all the wallpapers opaque since we want the visible from the start
                for (int i = wallpapers.length - 1; i >= 0; --i) {
                    t.setAlpha(wallpapers[i].leash, 1);
                }
                t.apply();
                mRecentsSession.setup(controller, info, finishedCallback, pausingTasks, pipTask,
                        recentsTask, recentsTaskId, leashMap, mToken,
                        (info.getFlags() & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0);
                recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0),
                        new Rect());
                mRecentsSession.start(controller, recents, mToken, info, t, finishedCallback);
            }

            @Override
            public void mergeAnimation(IBinder transition, TransitionInfo info,
                    SurfaceControl.Transaction t, IBinder mergeTarget,
                    IRemoteTransitionFinishedCallback finishedCallback) {
                if (mergeTarget.equals(mToken) && mRecentsSession.merge(info, t, recents)) {
                if (mergeTarget.equals(mToken) && mRecentsSession.merge(info, t)) {
                    try {
                        finishedCallback.onTransitionFinished(null /* wct */, null /* sct */);
                    } catch (RemoteException e) {
                        Log.e(TAG, "Error merging transition.", e);
                    }
                    // commit taskAppeared after merge transition finished.
                    mRecentsSession.commitTasksAppearedIfNeeded(recents);
                    mRecentsSession.commitTasksAppearedIfNeeded();
                } else {
                    t.close();
                    info.releaseAllSurfaces();
@@ -152,6 +104,7 @@ public class RemoteTransitionCompat {
     */
    @VisibleForTesting
    static class RecentsControllerWrap extends RecentsAnimationControllerCompat {
        private RecentsAnimationListener mListener = null;
        private RecentsAnimationControllerCompat mWrapped = null;
        private IRemoteTransitionFinishedCallback mFinishCB = null;
        private ArrayList<WindowContainerToken> mPausingTasks = null;
@@ -160,7 +113,7 @@ public class RemoteTransitionCompat {
        private int mRecentsTaskId = 0;
        private TransitionInfo mInfo = null;
        private ArrayList<SurfaceControl> mOpeningLeashes = null;
        private boolean mOpeningHome = false;
        private boolean mOpeningSeparateHome = false;
        private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null;
        private PictureInPictureSurfaceTransaction mPipTransaction = null;
        private IBinder mTransition = null;
@@ -168,34 +121,74 @@ public class RemoteTransitionCompat {
        private RemoteAnimationTarget[] mAppearedTargets;
        private boolean mWillFinishToHome = false;

        void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info,
                IRemoteTransitionFinishedCallback finishCB,
                ArrayList<WindowContainerToken> pausingTasks, WindowContainerToken pipTask,
                WindowContainerToken recentsTask, int recentsTaskId, ArrayMap<SurfaceControl,
                SurfaceControl> leashMap, IBinder transition, boolean keyguardLocked) {
        void start(RecentsAnimationControllerCompat wrapped, RecentsAnimationListener listener,
                IBinder transition, TransitionInfo info, SurfaceControl.Transaction t,
                IRemoteTransitionFinishedCallback finishedCallback) {
            if (mInfo != null) {
                throw new IllegalStateException("Trying to run a new recents animation while"
                        + " recents is already active.");
            }
            mListener = listener;
            mWrapped = wrapped;
            mInfo = info;
            mFinishCB = finishCB;
            mPausingTasks = pausingTasks;
            mPipTask = pipTask;
            mRecentsTask = recentsTask;
            mRecentsTaskId = recentsTaskId;
            mLeashMap = leashMap;
            mFinishCB = finishedCallback;
            mPausingTasks = new ArrayList<>();
            mPipTask = null;
            mRecentsTask = null;
            mRecentsTaskId = -1;
            mLeashMap = new ArrayMap<>();
            mTransition = transition;
            mKeyguardLocked = keyguardLocked;
            mKeyguardLocked = (info.getFlags() & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0;

            final RemoteAnimationTarget[] apps =
                    RemoteAnimationTargetCompat.wrapApps(info, t, mLeashMap);
            final RemoteAnimationTarget[] wallpapers =
                    RemoteAnimationTargetCompat.wrapNonApps(
                            info, true /* wallpapers */, t, mLeashMap);

            // This transition is for opening recents, so recents is on-top. We want to draw
            // the current going-away tasks on top of recents, though, so move them to front.
            // Note that we divide up the "layer space" into 3 regions each the size of
            // the change count. This way we can easily move changes into above/below/between
            // while maintaining their relative ordering.
            for (int i = apps.length - 1; i >= 0; --i) {
                final ActivityManager.RunningTaskInfo taskInfo = apps[i].taskInfo;
                if (apps[i].mode == MODE_CLOSING) {
                    t.setLayer(apps[i].leash, info.getChanges().size() * 3 - i);
                    if (taskInfo == null) {
                        continue;
                    }
                    // Add to front since we are iterating backwards.
                    mPausingTasks.add(0, taskInfo.token);
                    if (taskInfo.pictureInPictureParams != null
                            && taskInfo.pictureInPictureParams.isAutoEnterEnabled()) {
                        mPipTask = taskInfo.token;
                    }
                } else if (taskInfo != null
                        && taskInfo.topActivityType == ACTIVITY_TYPE_RECENTS) {
                    // This task is for recents, keep it on top.
                    t.setLayer(apps[i].leash, info.getChanges().size() * 3 - i);
                    mRecentsTask = taskInfo.token;
                    mRecentsTaskId = taskInfo.taskId;
                } else if (taskInfo != null && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
                    mRecentsTask = taskInfo.token;
                    mRecentsTaskId = taskInfo.taskId;
                }
            }
            // Also make all the wallpapers opaque since we want the visible from the start
            for (int i = wallpapers.length - 1; i >= 0; --i) {
                t.setAlpha(wallpapers[i].leash, 1);
            }
            t.apply();
            mListener.onAnimationStart(this, apps, wallpapers, new Rect(0, 0, 0, 0), new Rect());
        }

        @SuppressLint("NewApi")
        boolean merge(TransitionInfo info, SurfaceControl.Transaction t,
                RecentsAnimationListener recents) {
        boolean merge(TransitionInfo info, SurfaceControl.Transaction t) {
            SparseArray<TransitionInfo.Change> openingTasks = null;
            mAppearedTargets = null;
            boolean cancelRecents = false;
            boolean homeGoingAway = false;
            boolean foundHomeOpening = false;
            boolean foundRecentsClosing = false;
            boolean hasChangingApp = false;
            for (int i = info.getChanges().size() - 1; i >= 0; --i) {
                final TransitionInfo.Change change = info.getChanges().get(i);
@@ -203,8 +196,8 @@ public class RemoteTransitionCompat {
                    final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
                    if (taskInfo != null) {
                        if (taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
                            // canceling recents animation
                            cancelRecents = true;
                            // This is usually a 3p launcher
                            foundHomeOpening = true;
                        }
                        if (openingTasks == null) {
                            openingTasks = new SparseArray<>();
@@ -219,19 +212,18 @@ public class RemoteTransitionCompat {
                } else if (change.getMode() == TRANSIT_CLOSE
                        || change.getMode() == TRANSIT_TO_BACK) {
                    if (mRecentsTask.equals(change.getContainer())) {
                        homeGoingAway = true;
                        foundRecentsClosing = true;
                    }
                } else if (change.getMode() == TRANSIT_CHANGE) {
                    hasChangingApp = true;
                }
            }
            if (hasChangingApp && homeGoingAway) {
            if (hasChangingApp && foundRecentsClosing) {
                // This happens when a visible app is expanding (usually PiP). In this case,
                // The transition probably has a special-purpose animation, so finish recents
                // that transition probably has a special-purpose animation, so finish recents
                // now and let it do its animation (since recents is going to be occluded).
                if (!recents.onSwitchToScreenshot(() -> {
                    finish(true /* toHome */, false /* userLeaveHint */);
                })) {
                if (!mListener.onSwitchToScreenshot(
                        () -> finish(true /* toHome */, false /* userLeaveHint */))) {
                    Log.w(TAG, "Recents callback doesn't support support switching to screenshot"
                            + ", there might be a flicker.");
                    finish(true /* toHome */, false /* userLeaveHint */);
@@ -240,7 +232,7 @@ public class RemoteTransitionCompat {
            }
            if (openingTasks == null) return false;
            int pauseMatches = 0;
            if (!cancelRecents) {
            if (!foundHomeOpening) {
                for (int i = 0; i < openingTasks.size(); ++i) {
                    if (mPausingTasks.contains(openingTasks.valueAt(i).getContainer())) {
                        ++pauseMatches;
@@ -262,7 +254,7 @@ public class RemoteTransitionCompat {
            }
            final int layer = mInfo.getChanges().size() * 3;
            mOpeningLeashes = new ArrayList<>();
            mOpeningHome = cancelRecents;
            mOpeningSeparateHome = foundHomeOpening;
            final RemoteAnimationTarget[] targets =
                    new RemoteAnimationTarget[openingTasks.size()];
            for (int i = 0; i < openingTasks.size(); ++i) {
@@ -280,9 +272,9 @@ public class RemoteTransitionCompat {
            return true;
        }

        private void commitTasksAppearedIfNeeded(RecentsAnimationListener recents) {
        private void commitTasksAppearedIfNeeded() {
            if (mAppearedTargets != null) {
                recents.onTasksAppeared(mAppearedTargets);
                mListener.onTasksAppeared(mAppearedTargets);
                mAppearedTargets = null;
            }
        }
@@ -352,7 +344,7 @@ public class RemoteTransitionCompat {
                if (!mKeyguardLocked && mRecentsTask != null) {
                    wct.restoreTransientOrder(mRecentsTask);
                }
            } else if (toHome && mOpeningHome && mPausingTasks != null) {
            } else if (toHome && mOpeningSeparateHome && mPausingTasks != null) {
                // Special situaition where 3p launcher was changed during recents (this happens
                // during tapltests...). Here we get both "return to home" AND "home opening".
                // This is basically going home, but we have to restore recents order and also
@@ -404,11 +396,13 @@ public class RemoteTransitionCompat {
            mInfo.releaseAllSurfaces();
            // Reset all members.
            mWrapped = null;
            mListener = null;
            mFinishCB = null;
            mPausingTasks = null;
            mAppearedTargets = null;
            mInfo = null;
            mOpeningLeashes = null;
            mOpeningHome = false;
            mOpeningSeparateHome = false;
            mLeashMap = null;
            mTransition = null;
        }