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

Commit 619c9f7c authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Handle z-layering in animation layer

We use the prefix order to determine base layer within the
animation layer. This ensure that for the animation windows, the
z-ordering during animations doesn't change.

We then boost anything that needs a z-boost to 800570000 + prefix
order, such order within the boosted layers is preserved as well.

Also fix an issue where the thumbnail wasn't attached to the
animation layer.

Test: WindowContainerTests
Test: go/wm-smoke
Bug: 64674361
Change-Id: If5909bd87a12f1d8920c7232acab0f3d17be0f6c
parent 23ee71c8
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -141,7 +141,7 @@ class AppWindowThumbnail implements Animatable {

    @Override
    public Builder makeAnimationLeash() {
        return mAppToken.makeSurface();
        return mAppToken.makeSurface().setParent(mAppToken.getAppAnimationLayer());
    }

    @Override
+40 −2
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ import android.os.Trace;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
import android.view.SurfaceControl.Transaction;
import android.view.animation.Animation;
import android.view.IApplicationToken;
import android.view.SurfaceControl;
@@ -91,6 +92,11 @@ class AppTokenList extends ArrayList<AppWindowToken> {
class AppWindowToken extends WindowToken implements WindowManagerService.AppFreezeListener {
    private static final String TAG = TAG_WITH_CLASS_NAME ? "AppWindowToken" : TAG_WM;

    /**
     * Value to increment the z-layer when boosting a layer during animations. BOOST in l33tsp34k.
     */
    private static final int Z_BOOST_BASE = 800570000;

    // Non-null only for application tokens.
    final IApplicationToken appToken;

@@ -1537,11 +1543,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
                        new WindowAnimationSpec(a, mTmpPoint,
                                mService.mAppTransition.canSkipFirstFrame()),
                        mService.mSurfaceAnimationRunner);
                startAnimation(getPendingTransaction(), adapter, !isVisible());
                if (a.getZAdjustment() == Animation.ZORDER_TOP) {
                    mNeedsZBoost = true;
                    getDisplayContent().assignWindowLayers(false /* setLayoutNeeded */);
                }
                startAnimation(getPendingTransaction(), adapter, !isVisible());
                mTransit = transit;
                mTransitFlags = mService.mAppTransition.getTransitFlags();
                // TODO: Skip first frame and app stack clip mode.
@@ -1610,6 +1615,39 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
        return a;
    }

    @Override
    protected void setLayer(Transaction t, int layer) {
        if (!mSurfaceAnimator.hasLeash()) {
            t.setLayer(mSurfaceControl, layer);
        }
    }

    @Override
    protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
        if (!mSurfaceAnimator.hasLeash()) {
            t.setRelativeLayer(mSurfaceControl, relativeTo, layer);
        }
    }

    @Override
    protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) {
        if (!mSurfaceAnimator.hasLeash()) {
            t.reparent(mSurfaceControl, newParent.getHandle());
        }
    }

    @Override
    public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {

        // The leash is parented to the animation layer. We need to preserve the z-order by using
        // the prefix order index, but we boost if necessary.
        int layer = getPrefixOrderIndex();
        if (mNeedsZBoost) {
            layer += Z_BOOST_BASE;
        }
        leash.setLayer(layer);
    }

    /**
     * This must be called while inside a transaction.
     */
+78 −10
Original line number Diff line number Diff line
@@ -96,6 +96,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<

    private final Point mTmpPos = new Point();

    /** Total number of elements in this subtree, including our own hierarchy element. */
    private int mTreeWeight = 1;

    WindowContainer(WindowManagerService service) {
        mService = service;
        mPendingTransaction = service.mTransactionFactory.make();
@@ -157,7 +160,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
            // surface animator such that hierarchy is preserved when animating, i.e.
            // mSurfaceControl stays attached to the leash and we just reparent the leash to the
            // new parent.
            mSurfaceAnimator.reparent(getPendingTransaction(), mParent.mSurfaceControl);
            reparentSurfaceControl(getPendingTransaction(), mParent.mSurfaceControl);
        }

        // Either way we need to ask the parent to assign us a Z-order.
@@ -200,6 +203,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
        } else {
            mChildren.add(positionToAdd, child);
        }
        onChildAdded(child);

        // Set the parent after we've actually added a child in case a subclass depends on this.
        child.setParent(this);
    }
@@ -213,10 +218,21 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
                    + " can't add to container=" + getName());
        }
        mChildren.add(index, child);
        onChildAdded(child);

        // Set the parent after we've actually added a child in case a subclass depends on this.
        child.setParent(this);
    }

    private void onChildAdded(WindowContainer child) {
        mTreeWeight += child.mTreeWeight;
        WindowContainer parent = getParent();
        while (parent != null) {
            parent.mTreeWeight += child.mTreeWeight;
            parent = parent.getParent();
        }
    }

    /**
     * Removes the input child container from this container which is its parent.
     *
@@ -225,6 +241,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
    @CallSuper
    void removeChild(E child) {
        if (mChildren.remove(child)) {
            onChildRemoved(child);
            child.setParent(null);
        } else {
            throw new IllegalArgumentException("removeChild: container=" + child.getName()
@@ -232,6 +249,15 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
        }
    }

    private void onChildRemoved(WindowContainer child) {
        mTreeWeight -= child.mTreeWeight;
        WindowContainer parent = getParent();
        while (parent != null) {
            parent.mTreeWeight -= child.mTreeWeight;
            parent = parent.getParent();
        }
    }

    /**
     * Removes this window container and its children with no regard for what else might be going on
     * in the system. For example, the container will be removed during animation if this method is
@@ -246,7 +272,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
            // Need to do this after calling remove on the child because the child might try to
            // remove/detach itself from its parent which will cause an exception if we remove
            // it before calling remove on the child.
            mChildren.remove(child);
            if (mChildren.remove(child)) {
                onChildRemoved(child);
            }
        }

        if (mSurfaceControl != null) {
@@ -264,6 +292,34 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<

    }

    /**
     * @return The index of this element in the hierarchy tree in prefix order.
     */
    int getPrefixOrderIndex() {
        if (mParent == null) {
            return 0;
        }
        return mParent.getPrefixOrderIndex(this);
    }

    private int getPrefixOrderIndex(WindowContainer child) {
        int order = 0;
        for (int i = 0; i < mChildren.size(); i++) {
            final WindowContainer childI = mChildren.get(i);
            if (child == childI) {
                break;
            }
            order += childI.mTreeWeight;
        }
        if (mParent != null) {
            order += mParent.getPrefixOrderIndex(this);
        }

        // We also need to count ourselves.
        order++;
        return order;
    }

    /**
     * Removes this window container and its children taking care not to remove them during a
     * critical stage in the system. For example, some containers will not be removed during
@@ -831,10 +887,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
    void assignLayer(Transaction t, int layer) {
        final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
        if (mSurfaceControl != null && changed) {

            // Route through surface animator to accommodate that our surface control might be
            // attached to the leash, and leash is attached to parent container.
            mSurfaceAnimator.setLayer(t, layer);
            setLayer(t, layer);
            mLastLayer = layer;
            mLastRelativeToLayer = null;
        }
@@ -843,13 +896,28 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
    void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
        final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo;
        if (mSurfaceControl != null && changed) {
            setRelativeLayer(t, relativeTo, layer);
            mLastLayer = layer;
            mLastRelativeToLayer = relativeTo;
        }
    }

    protected void setLayer(Transaction t, int layer) {

        // Route through surface animator to accommodate that our surface control might be
        // attached to the leash, and leash is attached to parent container.
        mSurfaceAnimator.setLayer(t, layer);
    }

    protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {

        // Route through surface animator to accommodate that our surface control might be
        // attached to the leash, and leash is attached to parent container.
        mSurfaceAnimator.setRelativeLayer(t, relativeTo, layer);
            mLastLayer = layer;
            mLastRelativeToLayer = relativeTo;
    }

    protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) {
        mSurfaceAnimator.reparent(t, newParent);
    }

    void assignChildLayers(Transaction t) {
+80 −0
Original line number Diff line number Diff line
@@ -564,6 +564,86 @@ public class WindowContainerTests extends WindowTestsBase {
        assertEquals(1, child2223.compareTo(child21));
    }

    @Test
    public void testPrefixOrderIndex() throws Exception {
        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
        final TestWindowContainer root = builder.build();

        final TestWindowContainer child1 = root.addChildWindow();

        final TestWindowContainer child11 = child1.addChildWindow();
        final TestWindowContainer child12 = child1.addChildWindow();

        final TestWindowContainer child2 = root.addChildWindow();

        final TestWindowContainer child21 = child2.addChildWindow();
        final TestWindowContainer child22 = child2.addChildWindow();

        final TestWindowContainer child221 = child22.addChildWindow();
        final TestWindowContainer child222 = child22.addChildWindow();
        final TestWindowContainer child223 = child22.addChildWindow();

        final TestWindowContainer child23 = child2.addChildWindow();

        assertEquals(0, root.getPrefixOrderIndex());
        assertEquals(1, child1.getPrefixOrderIndex());
        assertEquals(2, child11.getPrefixOrderIndex());
        assertEquals(3, child12.getPrefixOrderIndex());
        assertEquals(4, child2.getPrefixOrderIndex());
        assertEquals(5, child21.getPrefixOrderIndex());
        assertEquals(6, child22.getPrefixOrderIndex());
        assertEquals(7, child221.getPrefixOrderIndex());
        assertEquals(8, child222.getPrefixOrderIndex());
        assertEquals(9, child223.getPrefixOrderIndex());
        assertEquals(10, child23.getPrefixOrderIndex());
    }

    @Test
    public void testPrefixOrder_addEntireSubtree() throws Exception {
        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
        final TestWindowContainer root = builder.build();
        final TestWindowContainer subtree = builder.build();
        final TestWindowContainer subtree2 = builder.build();

        final TestWindowContainer child1 = subtree.addChildWindow();
        final TestWindowContainer child11 = child1.addChildWindow();
        final TestWindowContainer child2 = subtree2.addChildWindow();
        final TestWindowContainer child3 = subtree2.addChildWindow();
        subtree.addChild(subtree2, 1);
        root.addChild(subtree, 0);

        assertEquals(0, root.getPrefixOrderIndex());
        assertEquals(1, subtree.getPrefixOrderIndex());
        assertEquals(2, child1.getPrefixOrderIndex());
        assertEquals(3, child11.getPrefixOrderIndex());
        assertEquals(4, subtree2.getPrefixOrderIndex());
        assertEquals(5, child2.getPrefixOrderIndex());
        assertEquals(6, child3.getPrefixOrderIndex());
    }

    @Test
    public void testPrefixOrder_remove() throws Exception {
        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
        final TestWindowContainer root = builder.build();

        final TestWindowContainer child1 = root.addChildWindow();

        final TestWindowContainer child11 = child1.addChildWindow();
        final TestWindowContainer child12 = child1.addChildWindow();

        final TestWindowContainer child2 = root.addChildWindow();

        assertEquals(0, root.getPrefixOrderIndex());
        assertEquals(1, child1.getPrefixOrderIndex());
        assertEquals(2, child11.getPrefixOrderIndex());
        assertEquals(3, child12.getPrefixOrderIndex());
        assertEquals(4, child2.getPrefixOrderIndex());

        root.removeChild(child1);

        assertEquals(1, child2.getPrefixOrderIndex());
    }

    /* Used so we can gain access to some protected members of the {@link WindowContainer} class */
    private class TestWindowContainer extends WindowContainer<TestWindowContainer> {
        private final int mLayer;