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

Commit 503c7046 authored by Robert Carr's avatar Robert Carr
Browse files

Allow relative layering of children

Initially we had hoped not to go down this route in order to produce the most
understandable model, but in the end it seems to be the most sane way to
satisfy some existing use cases from the WM. In particular we have the use
case of the IME. The IME may of course be larger than the application it is
targetting, in particular we see this in side by side split-screen portrait
and freeform. However, various UI features such as the text drag handles,
spell checking popups, etc, are controlled by the application process
and modelled as child windows of the application. This is a good fit for them
as they need to inherit most properties of the application window: Cropping,
Transform, Alpha. However they need to appear over the IME! As the IME can't
be a child of the application (it is bigger), we now see our use case for relative
layering. Perhaps the drag handles could be reimplemented as controlled by the IME
process but if nothing else as a legacy API we have exposed the idea of child windows
of the app going over the IME and are likely to need to continue to support it in some
mode.

Test: Transaction_test.cpp
Change-Id: If2d831bcbe88fc753b02c044a57882cca6ccffbb
parent 81be9993
Loading
Loading
Loading
Loading
+17 −4
Original line number Diff line number Diff line
@@ -1100,6 +1100,19 @@ bool Layer::setChildLayer(const sp<Layer>& childLayer, int32_t z) {
    return true;
}

bool Layer::setChildRelativeLayer(const sp<Layer>& childLayer,
        const sp<IBinder>& relativeToHandle, int32_t relativeZ) {
    ssize_t idx = mCurrentChildren.indexOf(childLayer);
    if (idx < 0) {
        return false;
    }
    if (childLayer->setRelativeLayer(relativeToHandle, relativeZ)) {
        mCurrentChildren.removeAt(idx);
        mCurrentChildren.add(childLayer);
    }
    return true;
}

bool Layer::setLayer(int32_t z) {
    if (mCurrentState.z == z) return false;
    mCurrentState.sequence++;
@@ -1601,11 +1614,7 @@ __attribute__((no_sanitize("unsigned-integer-overflow"))) LayerVector Layer::mak
    const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
    const State& state = useDrawing ? mDrawingState : mCurrentState;

    if (state.zOrderRelatives.size() == 0) {
        return children;
    }
    LayerVector traverse;

    for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
        sp<Layer> strongRelative = weakRelative.promote();
        if (strongRelative != nullptr) {
@@ -1614,6 +1623,10 @@ __attribute__((no_sanitize("unsigned-integer-overflow"))) LayerVector Layer::mak
    }

    for (const sp<Layer>& child : children) {
        const State& childState = useDrawing ? child->mDrawingState : child->mCurrentState;
        if (childState.zOrderRelativeOf != nullptr) {
            continue;
        }
        traverse.add(child);
    }

+2 −0
Original line number Diff line number Diff line
@@ -482,6 +482,8 @@ public:
    bool hasParent() const { return getParent() != nullptr; }
    Rect computeScreenBounds(bool reduceTransparentRegion = true) const;
    bool setChildLayer(const sp<Layer>& childLayer, int32_t z);
    bool setChildRelativeLayer(const sp<Layer>& childLayer,
            const sp<IBinder>& relativeToHandle, int32_t relativeZ);

    // Copy the current list of children to the drawing state. Called by
    // SurfaceFlinger to complete a transaction.
+15 −5
Original line number Diff line number Diff line
@@ -3107,12 +3107,22 @@ uint32_t SurfaceFlinger::setClientStateLocked(
        }
    }
    if (what & layer_state_t::eRelativeLayerChanged) {
        // NOTE: index needs to be calculated before we update the state
        const auto& p = layer->getParent();
        if (p == nullptr) {
            ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
        if (layer->setRelativeLayer(s.relativeLayerHandle, s.z)) {
            if (layer->setRelativeLayer(s.relativeLayerHandle, s.z) && idx >= 0) {
                mCurrentState.layersSortedByZ.removeAt(idx);
                mCurrentState.layersSortedByZ.add(layer);
                // we need traversal (state changed)
                // AND transaction (list changed)
                flags |= eTransactionNeeded|eTraversalNeeded;
            }
        } else {
            if (p->setChildRelativeLayer(layer, s.relativeLayerHandle, s.z)) {
                flags |= eTransactionNeeded|eTraversalNeeded;
            }
        }
    }
    if (what & layer_state_t::eSizeChanged) {
        if (layer->setSize(s.w, s.h)) {
+21 −0
Original line number Diff line number Diff line
@@ -1413,6 +1413,27 @@ TEST_F(ChildLayerTest, NestedChildren) {
    }
}

TEST_F(ChildLayerTest, ChildLayerRelativeLayer) {
    sp<SurfaceControl> relative = mComposerClient->createSurface(String8("Relative surface"),
            128, 128, PIXEL_FORMAT_RGBA_8888, 0);
    fillSurfaceRGBA8(relative, 255, 255, 255);

    Transaction t;
    t.setLayer(relative, INT32_MAX)
            .setRelativeLayer(mChild, relative->getHandle(), 1)
            .setPosition(mFGSurfaceControl, 0, 0)
            .apply(true);

    // We expect that the child should have been elevated above our
    // INT_MAX layer even though it's not a child of it.
    {
        ScreenCapture::captureScreen(&mCapture);
        mCapture->expectChildColor(0, 0);
        mCapture->expectChildColor(9, 9);
        mCapture->checkPixel(10, 10, 255, 255, 255);
    }
}

class LayerColorTest : public LayerUpdateTest {
 protected:
    void SetUp() override {