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

Commit 8365273c authored by Evan Rosky's avatar Evan Rosky Committed by Jiaming Liu
Browse files

Wrap Activity->Activity changes in non-activity transitions

When an Activity->Activity transition gets combined into a
non-activity transition, the anim-root no-longer properly
crops the activities and the activities also aren't offset
properly.

This fixes the offset by calculating offset from anim-root
instead of using endRelOffset (which is relative to the
true parent surface). Then, if it detects activity change
in non-activity task, it will create a wrapper surface.

Bug: 322113725
Test: use a test-app or otherwise have an activity->activity
      change happen at same time as translucent task closes.
Change-Id: I5e6c083e9c9f8c82ec8ffe6828d607fc019aeb59
(cherry picked from commit 163d0a7c)
parent dc577846
Loading
Loading
Loading
Loading
+41 −1
Original line number Diff line number Diff line
@@ -334,6 +334,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
        boolean isDisplayRotationAnimationStarted = false;
        final boolean isDreamTransition = isDreamTransition(info);
        final boolean isOnlyTranslucent = isOnlyTranslucent(info);
        final boolean isActivityLevel = isActivityLevelOnly(info);

        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
            final TransitionInfo.Change change = info.getChanges().get(i);
@@ -502,8 +503,35 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
                        : new Rect(change.getEndAbsBounds());
                clipRect.offsetTo(0, 0);

                final TransitionInfo.Root animRoot = TransitionUtil.getRootFor(change, info);
                final Point animRelOffset = new Point(
                        change.getEndAbsBounds().left - animRoot.getOffset().x,
                        change.getEndAbsBounds().top - animRoot.getOffset().y);
                if (change.getActivityComponent() != null && !isActivityLevel) {
                    // At this point, this is an independent activity change in a non-activity
                    // transition. This means that an activity transition got erroneously combined
                    // with another ongoing transition. This then means that the animation root may
                    // not tightly fit the activities, so we have to put them in a separate crop.
                    final int layer = Transitions.calculateAnimLayer(change, i,
                            info.getChanges().size(), info.getType());
                    final SurfaceControl leash = new SurfaceControl.Builder()
                            .setName("Transition ActivityWrap: "
                                    + change.getActivityComponent().toShortString())
                            .setParent(animRoot.getLeash())
                            .setContainerLayer().build();
                    startTransaction.setCrop(leash, clipRect);
                    startTransaction.setPosition(leash, animRelOffset.x, animRelOffset.y);
                    startTransaction.setLayer(leash, layer);
                    startTransaction.show(leash);
                    startTransaction.reparent(change.getLeash(), leash);
                    startTransaction.setPosition(change.getLeash(), 0, 0);
                    animRelOffset.set(0, 0);
                    finishTransaction.reparent(leash, null);
                    leash.release();
                }

                buildSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish,
                        mTransactionPool, mMainExecutor, change.getEndRelOffset(), cornerRadius,
                        mTransactionPool, mMainExecutor, animRelOffset, cornerRadius,
                        clipRect);

                if (info.getAnimationOptions() != null) {
@@ -612,6 +640,18 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
        return (translucentOpen + translucentClose) > 0;
    }

    /**
     * Does `info` only contain activity-level changes? This kinda assumes that if so, they are
     * all in one task.
     */
    private static boolean isActivityLevelOnly(@NonNull TransitionInfo info) {
        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
            final TransitionInfo.Change change = info.getChanges().get(i);
            if (change.getActivityComponent() == null) return false;
        }
        return true;
    }

    @Override
    public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
+43 −47
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import static android.view.WindowManager.fixScale;
import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED;
import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
import static android.window.TransitionInfo.FLAG_IS_OCCLUDED;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;
import static android.window.TransitionInfo.FLAG_NO_ANIMATION;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
@@ -530,78 +529,75 @@ public class Transitions implements RemoteCallable<Transitions>,
        }
    }

    /**
     * Reparents all participants into a shared parent and orders them based on: the global transit
     * type, their transit mode, and their destination z-order.
     */
    private static void setupAnimHierarchy(@NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl.Transaction finishT) {
        final int type = info.getType();
        final boolean isOpening = isOpeningType(type);
        final boolean isClosing = isClosingType(type);
        for (int i = 0; i < info.getRootCount(); ++i) {
            t.show(info.getRoot(i).getLeash());
        }
        final int numChanges = info.getChanges().size();
    static int calculateAnimLayer(@NonNull TransitionInfo.Change change, int i,
            int numChanges, @WindowManager.TransitionType int transitType) {
        // Put animating stuff above this line and put static stuff below it.
        final int zSplitLine = numChanges + 1;
        // changes should be ordered top-to-bottom in z
        for (int i = numChanges - 1; i >= 0; --i) {
            final TransitionInfo.Change change = info.getChanges().get(i);
            final SurfaceControl leash = change.getLeash();
        final boolean isOpening = isOpeningType(transitType);
        final boolean isClosing = isClosingType(transitType);
        final int mode = change.getMode();

            // Don't reparent anything that isn't independent within its parents
            if (!TransitionInfo.isIndependent(change, info)) {
                continue;
            }

            boolean hasParent = change.getParent() != null;

            final int rootIdx = TransitionUtil.rootIndexFor(change, info);
            if (!hasParent) {
                t.reparent(leash, info.getRoot(rootIdx).getLeash());
                t.setPosition(leash,
                        change.getStartAbsBounds().left - info.getRoot(rootIdx).getOffset().x,
                        change.getStartAbsBounds().top - info.getRoot(rootIdx).getOffset().y);
            }
            final int layer;
        // Put all the OPEN/SHOW on top
            if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
                // Wallpaper is always at the bottom, opening wallpaper on top of closing one.
        if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
                    layer = -zSplitLine + numChanges - i;
                } else {
                    layer = -zSplitLine - i;
                }
            } else if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
            if (isOpening
                    // This is for when an activity launches while a different transition is
                    // collecting.
                    || change.hasFlags(FLAG_MOVED_TO_TOP)) {
                // put on top
                    layer = zSplitLine + numChanges - i;
                return zSplitLine + numChanges - i;
            } else {
                // put on bottom
                    layer = zSplitLine - i;
                return zSplitLine - i;
            }
        } else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
            if (isOpening) {
                // put on bottom and leave visible
                    layer = zSplitLine - i;
                return zSplitLine - i;
            } else {
                // put on top
                    layer = zSplitLine + numChanges - i;
                return zSplitLine + numChanges - i;
            }
        } else { // CHANGE or other
            if (isClosing || TransitionUtil.isOrderOnly(change)) {
                // Put below CLOSE mode (in the "static" section).
                    layer = zSplitLine - i;
                return zSplitLine - i;
            } else {
                // Put above CLOSE mode.
                    layer = zSplitLine + numChanges - i;
                return zSplitLine + numChanges - i;
            }
        }
    }

    /**
     * Reparents all participants into a shared parent and orders them based on: the global transit
     * type, their transit mode, and their destination z-order.
     */
    private static void setupAnimHierarchy(@NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl.Transaction finishT) {
        final int type = info.getType();
        for (int i = 0; i < info.getRootCount(); ++i) {
            t.show(info.getRoot(i).getLeash());
        }
        final int numChanges = info.getChanges().size();
        // changes should be ordered top-to-bottom in z
        for (int i = numChanges - 1; i >= 0; --i) {
            final TransitionInfo.Change change = info.getChanges().get(i);
            final SurfaceControl leash = change.getLeash();

            // Don't reparent anything that isn't independent within its parents
            if (!TransitionInfo.isIndependent(change, info)) {
                continue;
            }

            boolean hasParent = change.getParent() != null;

            final TransitionInfo.Root root = TransitionUtil.getRootFor(change, info);
            if (!hasParent) {
                t.reparent(leash, root.getLeash());
                t.setPosition(leash,
                        change.getStartAbsBounds().left - root.getOffset().x,
                        change.getStartAbsBounds().top - root.getOffset().y);
            }
            final int layer = calculateAnimLayer(change, i, numChanges, type);
            t.setLayer(leash, layer);
        }
    }