| /* |
| * Copyright (C) 2020 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #pragma clang diagnostic push |
| #pragma clang diagnostic ignored "-Wconversion" |
| |
| #include "LayerTransactionTest.h" |
| |
| namespace android { |
| |
| class DetachChildren : public LayerTransactionTest { |
| protected: |
| virtual void SetUp() { |
| LayerTransactionTest::SetUp(); |
| |
| mMainSurface = createLayer(String8("Main Test Surface"), mMainSurfaceBounds.width(), |
| mMainSurfaceBounds.height(), 0, mBlackBgSurface.get()); |
| |
| ASSERT_TRUE(mMainSurface != nullptr); |
| ASSERT_TRUE(mMainSurface->isValid()); |
| |
| TransactionUtils::fillSurfaceRGBA8(mMainSurface, mMainSurfaceColor); |
| |
| asTransaction([&](Transaction& t) { |
| t.setLayer(mMainSurface, INT32_MAX - 1) |
| .setPosition(mMainSurface, mMainSurfaceBounds.left, mMainSurfaceBounds.top) |
| .show(mMainSurface); |
| }); |
| } |
| |
| virtual void TearDown() { |
| LayerTransactionTest::TearDown(); |
| mMainSurface = 0; |
| } |
| |
| sp<SurfaceControl> mMainSurface; |
| Color mMainSurfaceColor = {195, 63, 63, 255}; |
| Rect mMainSurfaceBounds = Rect(64, 64, 128, 128); |
| std::unique_ptr<ScreenCapture> mCapture; |
| }; |
| |
| TEST_F(DetachChildren, RelativesAreNotDetached) { |
| Color relativeColor = {10, 10, 10, 255}; |
| Rect relBounds = Rect(64, 64, 74, 74); |
| |
| sp<SurfaceControl> relative = |
| createLayer(String8("relativeTestSurface"), relBounds.width(), relBounds.height(), 0); |
| TransactionUtils::fillSurfaceRGBA8(relative, relativeColor); |
| |
| Transaction{} |
| .setRelativeLayer(relative, mMainSurface->getHandle(), 1) |
| .setPosition(relative, relBounds.left, relBounds.top) |
| .apply(); |
| |
| { |
| // The relative should be on top of the FG control. |
| mCapture = screenshot(); |
| mCapture->expectColor(relBounds, relativeColor); |
| } |
| Transaction{}.detachChildren(mMainSurface).apply(); |
| |
| { |
| // Nothing should change at this point. |
| mCapture = screenshot(); |
| mCapture->expectColor(relBounds, relativeColor); |
| } |
| |
| Transaction{}.hide(relative).apply(); |
| |
| { |
| // Ensure that the relative was actually hidden, rather than |
| // being left in the detached but visible state. |
| mCapture = screenshot(); |
| mCapture->expectColor(mMainSurfaceBounds, mMainSurfaceColor); |
| } |
| } |
| |
| TEST_F(DetachChildren, DetachChildrenSameClient) { |
| Color childColor = {200, 200, 200, 255}; |
| Rect childBounds = Rect(74, 74, 84, 84); |
| sp<SurfaceControl> child = createLayer(String8("Child surface"), childBounds.width(), |
| childBounds.height(), 0, mMainSurface.get()); |
| ASSERT_TRUE(child->isValid()); |
| |
| TransactionUtils::fillSurfaceRGBA8(child, childColor); |
| |
| asTransaction([&](Transaction& t) { |
| t.show(child); |
| t.setPosition(child, childBounds.left - mMainSurfaceBounds.left, |
| childBounds.top - mMainSurfaceBounds.top); |
| }); |
| |
| { |
| mCapture = screenshot(); |
| // Expect main color around the child surface |
| mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| mCapture->expectColor(childBounds, childColor); |
| } |
| |
| asTransaction([&](Transaction& t) { t.detachChildren(mMainSurface); }); |
| |
| asTransaction([&](Transaction& t) { t.hide(child); }); |
| |
| // Since the child has the same client as the parent, it will not get |
| // detached and will be hidden. |
| { |
| mCapture = screenshot(); |
| mCapture->expectColor(mMainSurfaceBounds, mMainSurfaceColor); |
| } |
| } |
| |
| TEST_F(DetachChildren, DetachChildrenDifferentClient) { |
| Color childColor = {200, 200, 200, 255}; |
| Rect childBounds = Rect(74, 74, 84, 84); |
| |
| sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient; |
| sp<SurfaceControl> childNewClient = |
| createSurface(newComposerClient, "New Child Test Surface", childBounds.width(), |
| childBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get()); |
| ASSERT_TRUE(childNewClient->isValid()); |
| |
| TransactionUtils::fillSurfaceRGBA8(childNewClient, childColor); |
| |
| asTransaction([&](Transaction& t) { |
| t.show(childNewClient); |
| t.setPosition(childNewClient, childBounds.left - mMainSurfaceBounds.left, |
| childBounds.top - mMainSurfaceBounds.top); |
| }); |
| |
| { |
| mCapture = screenshot(); |
| // Expect main color around the child surface |
| mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| mCapture->expectColor(childBounds, childColor); |
| } |
| |
| asTransaction([&](Transaction& t) { t.detachChildren(mMainSurface); }); |
| |
| asTransaction([&](Transaction& t) { t.hide(childNewClient); }); |
| |
| // Nothing should have changed. |
| { |
| mCapture = screenshot(); |
| mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| mCapture->expectColor(childBounds, childColor); |
| } |
| } |
| |
| TEST_F(DetachChildren, DetachChildrenThenAttach) { |
| Color childColor = {200, 200, 200, 255}; |
| Rect childBounds = Rect(74, 74, 84, 84); |
| |
| sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient; |
| sp<SurfaceControl> childNewClient = |
| createSurface(newComposerClient, "New Child Test Surface", childBounds.width(), |
| childBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get()); |
| ASSERT_TRUE(childNewClient->isValid()); |
| |
| TransactionUtils::fillSurfaceRGBA8(childNewClient, childColor); |
| |
| Transaction() |
| .show(childNewClient) |
| .setPosition(childNewClient, childBounds.left - mMainSurfaceBounds.left, |
| childBounds.top - mMainSurfaceBounds.top) |
| .apply(); |
| |
| { |
| mCapture = screenshot(); |
| // Expect main color around the child surface |
| mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| mCapture->expectColor(childBounds, childColor); |
| } |
| |
| Transaction().detachChildren(mMainSurface).apply(); |
| Transaction().hide(childNewClient).apply(); |
| |
| // Nothing should have changed. |
| { |
| mCapture = screenshot(); |
| mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| mCapture->expectColor(childBounds, childColor); |
| } |
| |
| Color newParentColor = Color::RED; |
| Rect newParentBounds = Rect(20, 20, 52, 52); |
| sp<SurfaceControl> newParentSurface = |
| createLayer(String8("New Parent Surface"), newParentBounds.width(), |
| newParentBounds.height(), 0); |
| TransactionUtils::fillSurfaceRGBA8(newParentSurface, newParentColor); |
| Transaction() |
| .setLayer(newParentSurface, INT32_MAX - 1) |
| .show(newParentSurface) |
| .setPosition(newParentSurface, newParentBounds.left, newParentBounds.top) |
| .reparent(childNewClient, newParentSurface->getHandle()) |
| .apply(); |
| { |
| mCapture = screenshot(); |
| // Child is now hidden. |
| mCapture->expectColor(newParentBounds, newParentColor); |
| } |
| } |
| |
| TEST_F(DetachChildren, DetachChildrenWithDeferredTransaction) { |
| Color childColor = {200, 200, 200, 255}; |
| Rect childBounds = Rect(74, 74, 84, 84); |
| |
| sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient; |
| sp<SurfaceControl> childNewClient = |
| createSurface(newComposerClient, "New Child Test Surface", childBounds.width(), |
| childBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get()); |
| ASSERT_TRUE(childNewClient->isValid()); |
| |
| TransactionUtils::fillSurfaceRGBA8(childNewClient, childColor); |
| |
| Transaction() |
| .show(childNewClient) |
| .setPosition(childNewClient, childBounds.left - mMainSurfaceBounds.left, |
| childBounds.top - mMainSurfaceBounds.top) |
| .apply(); |
| |
| { |
| mCapture = screenshot(); |
| mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| mCapture->expectColor(childBounds, childColor); |
| } |
| |
| Transaction() |
| .deferTransactionUntil_legacy(childNewClient, mMainSurface->getHandle(), |
| mMainSurface->getSurface()->getNextFrameNumber()) |
| .apply(); |
| Transaction().detachChildren(mMainSurface).apply(); |
| ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(mMainSurface, Color::RED, |
| mMainSurfaceBounds.width(), |
| mMainSurfaceBounds.height())); |
| |
| // BufferLayer can still dequeue buffers even though there's a detached layer with a |
| // deferred transaction. |
| { |
| SCOPED_TRACE("new buffer"); |
| mCapture = screenshot(); |
| mCapture->expectBorder(childBounds, Color::RED); |
| mCapture->expectColor(childBounds, childColor); |
| } |
| } |
| |
| TEST_F(DetachChildren, ReparentParentLayerOfDetachedChildren) { |
| Color childColor = {200, 200, 200, 255}; |
| Rect childBounds = Rect(74, 74, 94, 94); |
| Color grandchildColor = Color::RED; |
| Rect grandchildBounds = Rect(80, 80, 90, 90); |
| |
| sp<SurfaceComposerClient> newClient1 = new SurfaceComposerClient; |
| sp<SurfaceComposerClient> newClient2 = new SurfaceComposerClient; |
| |
| sp<SurfaceControl> childSurface = |
| createSurface(newClient1, "Child surface", childBounds.width(), childBounds.height(), |
| PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get()); |
| sp<SurfaceControl> grandchildSurface = |
| createSurface(newClient2, "Grandchild Surface", grandchildBounds.width(), |
| grandchildBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, childSurface.get()); |
| |
| TransactionUtils::fillSurfaceRGBA8(childSurface, childColor); |
| TransactionUtils::fillSurfaceRGBA8(grandchildSurface, grandchildColor); |
| |
| Transaction() |
| .show(childSurface) |
| .show(grandchildSurface) |
| .setPosition(childSurface, childBounds.left - mMainSurfaceBounds.left, |
| childBounds.top - mMainSurfaceBounds.top) |
| .setPosition(grandchildSurface, grandchildBounds.left - childBounds.left, |
| grandchildBounds.top - childBounds.top) |
| .apply(); |
| |
| { |
| mCapture = screenshot(); |
| mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| mCapture->expectBorder(grandchildBounds, childColor); |
| mCapture->expectColor(grandchildBounds, grandchildColor); |
| } |
| |
| Transaction().detachChildren(childSurface).apply(); |
| |
| // Remove main surface offscreen |
| Transaction().reparent(mMainSurface, nullptr).apply(); |
| { |
| mCapture = screenshot(); |
| mCapture->expectColor(mMainSurfaceBounds, Color::BLACK); |
| } |
| |
| Transaction().reparent(mMainSurface, mBlackBgSurface->getHandle()).apply(); |
| { |
| mCapture = screenshot(); |
| mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| mCapture->expectBorder(grandchildBounds, childColor); |
| mCapture->expectColor(grandchildBounds, grandchildColor); |
| } |
| |
| Transaction().hide(grandchildSurface).apply(); |
| |
| // grandchild is still detached so it will not hide |
| { |
| mCapture = screenshot(); |
| mCapture->expectBorder(childBounds, mMainSurfaceColor); |
| mCapture->expectBorder(grandchildBounds, childColor); |
| mCapture->expectColor(grandchildBounds, grandchildColor); |
| } |
| } |
| |
| } // namespace android |